text:
"""Minimal Python 2 & 3 shim around all Qt bindings

DOCUMENTATION
    Qt.py was born in the film and visual effects industry to address
    the growing need for the development of software capable of running
    with more than one flavour of the Qt bindings for Python - PySide,
    PySide2, PyQt4 and PyQt5.

    1. Build for one, run with all
    2. Explicit is better than implicit
    3. Support co-existence

    Default resolution order:
        - PySide2
        - PyQt5
        - PySide
        - PyQt4

    Usage:
        >> import sys
        >> from Qt import QtWidgets
        >> app = QtWidgets.QApplication(sys.argv)
        >> button = QtWidgets.QPushButton("Hello World")
        >> button.show()
        >> app.exec_()

    All members of PySide2 are mapped from other bindings, should they exist.
    If no equivalent member exist, it is excluded from Qt.py and inaccessible.
    The idea is to highlight members that exist across all supported binding,
    and guarantee that code that runs on one binding runs on all others.

    For more details, visit https://github.com/mottosso/Qt.py

LICENSE

    See end of file for license (MIT, BSD) information.

"""

import os
import sys
import types
import shutil
import importlib

__version__ = "1.1.0.b1"

# Enable support for `from Qt import *`
__all__ = []

# Flags from environment variables
QT_VERBOSE = bool(os.getenv("QT_VERBOSE"))
QT_PREFERRED_BINDING = os.getenv("QT_PREFERRED_BINDING", "")
QT_SIP_API_HINT = os.getenv("QT_SIP_API_HINT")

# Reference to Qt.py
Qt = sys.modules[__name__]
Qt.QtCompat = types.ModuleType("QtCompat")

try:
    long
except NameError:
    # Python 3 compatibility
    long = int

"""Common members of all bindings

This is where each member of Qt.py is explicitly defined.
It is based on a "lowest common denominator" of all bindings;
including members found in each of the 4 bindings.

Find or add excluded members in build_membership.py

"""

_common_members = {
    "QtGui": [
        "QAbstractTextDocumentLayout",
        "QActionEvent",
        "QBitmap",
        "QBrush",
        "QClipboard",
        "QCloseEvent",
        "QColor",
        "QConicalGradient",
        "QContextMenuEvent",
        "QCursor",
        "QDoubleValidator",
        "QDrag",
        "QDragEnterEvent",
        "QDragLeaveEvent",
        "QDragMoveEvent",
        "QDropEvent",
        "QFileOpenEvent",
        "QFocusEvent",
        "QFont",
        "QFontDatabase",
        "QFontInfo",
        "QFontMetrics",
        "QFontMetricsF",
        "QGradient",
        "QHelpEvent",
        "QHideEvent",
        "QHoverEvent",
        "QIcon",
        "QIconDragEvent",
        "QIconEngine",
        "QImage",
        "QImageIOHandler",
        "QImageReader",
        "QImageWriter",
        "QInputEvent",
        "QInputMethodEvent",
        "QIntValidator",
        "QKeyEvent",
        "QKeySequence",
        "QLinearGradient",
        "QMatrix2x2",
        "QMatrix2x3",
        "QMatrix2x4",
        "QMatrix3x2",
        "QMatrix3x3",
        "QMatrix3x4",
        "QMatrix4x2",
        "QMatrix4x3",
        "QMatrix4x4",
        "QMouseEvent",
        "QMoveEvent",
        "QMovie",
        "QPaintDevice",
        "QPaintEngine",
        "QPaintEngineState",
        "QPaintEvent",
        "QPainter",
        "QPainterPath",
        "QPainterPathStroker",
        "QPalette",
        "QPen",
        "QPicture",
        "QPictureIO",
        "QPixmap",
        "QPixmapCache",
        "QPolygon",
        "QPolygonF",
        "QQuaternion",
        "QRadialGradient",
        "QRegExpValidator",
        "QRegion",
        "QResizeEvent",
        "QSessionManager",
        "QShortcutEvent",
        "QShowEvent",
        "QStandardItem",
        "QStandardItemModel",
        "QStatusTipEvent",
        "QSyntaxHighlighter",
        "QTabletEvent",
        "QTextBlock",
        "QTextBlockFormat",
        "QTextBlockGroup",
        "QTextBlockUserData",
        "QTextCharFormat",
        "QTextCursor",
        "QTextDocument",
        "QTextDocumentFragment",
        "QTextFormat",
        "QTextFragment",
        "QTextFrame",
        "QTextFrameFormat",
        "QTextImageFormat",
        "QTextInlineObject",
        "QTextItem",
        "QTextLayout",
        "QTextLength",
        "QTextLine",
        "QTextList",
        "QTextListFormat",
        "QTextObject",
        "QTextObjectInterface",
        "QTextOption",
        "QTextTable",
        "QTextTableCell",
        "QTextTableCellFormat",
        "QTextTableFormat",
        "QTransform",
        "QValidator",
        "QVector2D",
        "QVector3D",
        "QVector4D",
        "QWhatsThisClickedEvent",
        "QWheelEvent",
        "QWindowStateChangeEvent",
        "qAlpha",
        "qBlue",
        "qGray",
        "qGreen",
        "qIsGray",
        "qRed",
        "qRgb",
        "qRgb",
    ],
    "QtWidgets": [
        "QAbstractButton",
        "QAbstractGraphicsShapeItem",
        "QAbstractItemDelegate",
        "QAbstractItemView",
        "QAbstractScrollArea",
        "QAbstractSlider",
        "QAbstractSpinBox",
        "QAction",
        "QActionGroup",
        "QApplication",
        "QBoxLayout",
        "QButtonGroup",
        "QCalendarWidget",
        "QCheckBox",
        "QColorDialog",
        "QColumnView",
        "QComboBox",
        "QCommandLinkButton",
        "QCommonStyle",
        "QCompleter",
        "QDataWidgetMapper",
        "QDateEdit",
        "QDateTimeEdit",
        "QDesktopWidget",
        "QDial",
        "QDialog",
        "QDialogButtonBox",
        "QDirModel",
        "QDockWidget",
        "QDoubleSpinBox",
        "QErrorMessage",
        "QFileDialog",
        "QFileIconProvider",
        "QFileSystemModel",
        "QFocusFrame",
        "QFontComboBox",
        "QFontDialog",
        "QFormLayout",
        "QFrame",
        "QGesture",
        "QGestureEvent",
        "QGestureRecognizer",
        "QGraphicsAnchor",
        "QGraphicsAnchorLayout",
        "QGraphicsBlurEffect",
        "QGraphicsColorizeEffect",
        "QGraphicsDropShadowEffect",
        "QGraphicsEffect",
        "QGraphicsEllipseItem",
        "QGraphicsGridLayout",
        "QGraphicsItem",
        "QGraphicsItemGroup",
        "QGraphicsLayout",
        "QGraphicsLayoutItem",
        "QGraphicsLineItem",
        "QGraphicsLinearLayout",
        "QGraphicsObject",
        "QGraphicsOpacityEffect",
        "QGraphicsPathItem",
        "QGraphicsPixmapItem",
        "QGraphicsPolygonItem",
        "QGraphicsProxyWidget",
        "QGraphicsRectItem",
        "QGraphicsRotation",
        "QGraphicsScale",
        "QGraphicsScene",
        "QGraphicsSceneContextMenuEvent",
        "QGraphicsSceneDragDropEvent",
        "QGraphicsSceneEvent",
        "QGraphicsSceneHelpEvent",
        "QGraphicsSceneHoverEvent",
        "QGraphicsSceneMouseEvent",
        "QGraphicsSceneMoveEvent",
        "QGraphicsSceneResizeEvent",
        "QGraphicsSceneWheelEvent",
        "QGraphicsSimpleTextItem",
        "QGraphicsTextItem",
        "QGraphicsTransform",
        "QGraphicsView",
        "QGraphicsWidget",
        "QGridLayout",
        "QGroupBox",
        "QHBoxLayout",
        "QHeaderView",
        "QInputDialog",
        "QItemDelegate",
        "QItemEditorCreatorBase",
        "QItemEditorFactory",
        "QKeyEventTransition",
        "QLCDNumber",
        "QLabel",
        "QLayout",
        "QLayoutItem",
        "QLineEdit",
        "QListView",
        "QListWidget",
        "QListWidgetItem",
        "QMainWindow",
        "QMdiArea",
        "QMdiSubWindow",
        "QMenu",
        "QMenuBar",
        "QMessageBox",
        "QMouseEventTransition",
        "QPanGesture",
        "QPinchGesture",
        "QPlainTextDocumentLayout",
        "QPlainTextEdit",
        "QProgressBar",
        "QProgressDialog",
        "QPushButton",
        "QRadioButton",
        "QRubberBand",
        "QScrollArea",
        "QScrollBar",
        "QShortcut",
        "QSizeGrip",
        "QSizePolicy",
        "QSlider",
        "QSpacerItem",
        "QSpinBox",
        "QSplashScreen",
        "QSplitter",
        "QSplitterHandle",
        "QStackedLayout",
        "QStackedWidget",
        "QStatusBar",
        "QStyle",
        "QStyleFactory",
        "QStyleHintReturn",
        "QStyleHintReturnMask",
        "QStyleHintReturnVariant",
        "QStyleOption",
        "QStyleOptionButton",
        "QStyleOptionComboBox",
        "QStyleOptionComplex",
        "QStyleOptionDockWidget",
        "QStyleOptionFocusRect",
        "QStyleOptionFrame",
        "QStyleOptionGraphicsItem",
        "QStyleOptionGroupBox",
        "QStyleOptionHeader",
        "QStyleOptionMenuItem",
        "QStyleOptionProgressBar",
        "QStyleOptionRubberBand",
        "QStyleOptionSizeGrip",
        "QStyleOptionSlider",
        "QStyleOptionSpinBox",
        "QStyleOptionTab",
        "QStyleOptionTabBarBase",
        "QStyleOptionTabWidgetFrame",
        "QStyleOptionTitleBar",
        "QStyleOptionToolBar",
        "QStyleOptionToolBox",
        "QStyleOptionToolButton",
        "QStyleOptionViewItem",
        "QStylePainter",
        "QStyledItemDelegate",
        "QSwipeGesture",
        "QSystemTrayIcon",
        "QTabBar",
        "QTabWidget",
        "QTableView",
        "QTableWidget",
        "QTableWidgetItem",
        "QTableWidgetSelectionRange",
        "QTapAndHoldGesture",
        "QTapGesture",
        "QTextBrowser",
        "QTextEdit",
        "QTimeEdit",
        "QToolBar",
        "QToolBox",
        "QToolButton",
        "QToolTip",
        "QTreeView",
        "QTreeWidget",
        "QTreeWidgetItem",
        "QTreeWidgetItemIterator",
        "QUndoCommand",
        "QUndoGroup",
        "QUndoStack",
        "QUndoView",
        "QVBoxLayout",
        "QWhatsThis",
        "QWidget",
        "QWidgetAction",
        "QWidgetItem",
        "QWizard",
        "QWizardPage",
    ],
    "QtCore": [
        "QAbstractAnimation",
        "QAbstractEventDispatcher",
        "QAbstractItemModel",
        "QAbstractListModel",
        "QAbstractState",
        "QAbstractTableModel",
        "QAbstractTransition",
        "QAnimationGroup",
        "QBasicTimer",
        "QBitArray",
        "QBuffer",
        "QByteArray",
        "QByteArrayMatcher",
        "QChildEvent",
        "QCoreApplication",
        "QCryptographicHash",
        "QDataStream",
        "QDate",
        "QDateTime",
        "QDir",
        "QDirIterator",
        "QDynamicPropertyChangeEvent",
        "QEasingCurve",
        "QElapsedTimer",
        "QEvent",
        "QEventLoop",
        "QEventTransition",
        "QFile",
        "QFileInfo",
        "QFileSystemWatcher",
        "QFinalState",
        "QGenericArgument",
        "QGenericReturnArgument",
        "QHistoryState",
        "QIODevice",
        "QLibraryInfo",
        "QLine",
        "QLineF",
        "QLocale",
        "QMargins",
        "QMetaClassInfo",
        "QMetaEnum",
        "QMetaMethod",
        "QMetaObject",
        "QMetaProperty",
        "QMetaType",
        "QMimeData",
        "QModelIndex",
        "QMutex",
        "QMutexLocker",
        "QObject",
        "QParallelAnimationGroup",
        "QPauseAnimation",
        "QPersistentModelIndex",
        "QPluginLoader",
        "QPoint",
        "QPointF",
        "QProcess",
        "QProcessEnvironment",
        "QPropertyAnimation",
        "QReadLocker",
        "QReadWriteLock",
        "QRect",
        "QRectF",
        "QRegExp",
        "QResource",
        "QRunnable",
        "QSemaphore",
        "QSequentialAnimationGroup",
        "QSettings",
        "QSignalMapper",
        "QSignalTransition",
        "QSize",
        "QSizeF",
        "QSocketNotifier",
        "QState",
        "QStateMachine",
        "QSysInfo",
        "QSystemSemaphore",
        "QTemporaryFile",
        "QTextBoundaryFinder",
        "QTextCodec",
        "QTextDecoder",
        "QTextEncoder",
        "QTextStream",
        "QTextStreamManipulator",
        "QThread",
        "QThreadPool",
        "QTime",
        "QTimeLine",
        "QTimer",
        "QTimerEvent",
        "QTranslator",
        "QUrl",
        "QVariantAnimation",
        "QWaitCondition",
        "QWriteLocker",
        "QXmlStreamAttribute",
        "QXmlStreamAttributes",
        "QXmlStreamEntityDeclaration",
        "QXmlStreamEntityResolver",
        "QXmlStreamNamespaceDeclaration",
        "QXmlStreamNotationDeclaration",
        "QXmlStreamReader",
        "QXmlStreamWriter",
        "Qt",
        "QtCriticalMsg",
        "QtDebugMsg",
        "QtFatalMsg",
        "QtMsgType",
        "QtSystemMsg",
        "QtWarningMsg",
        "qAbs",
        "qAddPostRoutine",
        "qChecksum",
        "qCritical",
        "qDebug",
        "qFatal",
        "qFuzzyCompare",
        "qIsFinite",
        "qIsInf",
        "qIsNaN",
        "qIsNull",
        "qRegisterResourceData",
        "qUnregisterResourceData",
        "qVersion",
        "qWarning",
        "qrand",
        "qsrand",
    ],
    "QtXml": [
        "QDomAttr",
        "QDomCDATASection",
        "QDomCharacterData",
        "QDomComment",
        "QDomDocument",
        "QDomDocumentFragment",
        "QDomDocumentType",
        "QDomElement",
        "QDomEntity",
        "QDomEntityReference",
        "QDomImplementation",
        "QDomNamedNodeMap",
        "QDomNode",
        "QDomNodeList",
        "QDomNotation",
        "QDomProcessingInstruction",
        "QDomText",
        "QXmlAttributes",
        "QXmlContentHandler",
        "QXmlDTDHandler",
        "QXmlDeclHandler",
        "QXmlDefaultHandler",
        "QXmlEntityResolver",
        "QXmlErrorHandler",
        "QXmlInputSource",
        "QXmlLexicalHandler",
        "QXmlLocator",
        "QXmlNamespaceSupport",
        "QXmlParseException",
        "QXmlReader",
        "QXmlSimpleReader"
    ],
    "QtHelp": [
        "QHelpContentItem",
        "QHelpContentModel",
        "QHelpContentWidget",
        "QHelpEngine",
        "QHelpEngineCore",
        "QHelpIndexModel",
        "QHelpIndexWidget",
        "QHelpSearchEngine",
        "QHelpSearchQuery",
        "QHelpSearchQueryWidget",
        "QHelpSearchResultWidget"
    ],
    "QtNetwork": [
        "QAbstractNetworkCache",
        "QAbstractSocket",
        "QAuthenticator",
        "QHostAddress",
        "QHostInfo",
        "QLocalServer",
        "QLocalSocket",
        "QNetworkAccessManager",
        "QNetworkAddressEntry",
        "QNetworkCacheMetaData",
        "QNetworkConfiguration",
        "QNetworkConfigurationManager",
        "QNetworkCookie",
        "QNetworkCookieJar",
        "QNetworkDiskCache",
        "QNetworkInterface",
        "QNetworkProxy",
        "QNetworkProxyFactory",
        "QNetworkProxyQuery",
        "QNetworkReply",
        "QNetworkRequest",
        "QNetworkSession",
        "QSsl",
        "QTcpServer",
        "QTcpSocket",
        "QUdpSocket"
    ],
    "QtOpenGL": [
        "QGL",
        "QGLContext",
        "QGLFormat",
        "QGLWidget"
    ]
}

"""Misplaced members

These members from the original submodule are misplaced relative PySide2

"""
_misplaced_members = {
    "pyside2": {
        "QtGui.QStringListModel": "QtCore.QStringListModel",
        "QtCore.Property": "QtCore.Property",
        "QtCore.Signal": "QtCore.Signal",
        "QtCore.Slot": "QtCore.Slot",
        "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
        "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
        "QtCore.QItemSelection": "QtCore.QItemSelection",
        "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel",
    },
    "pyqt5": {
        "QtCore.pyqtProperty": "QtCore.Property",
        "QtCore.pyqtSignal": "QtCore.Signal",
        "QtCore.pyqtSlot": "QtCore.Slot",
        "QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
        "QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
        "QtCore.QStringListModel": "QtCore.QStringListModel",
        "QtCore.QItemSelection": "QtCore.QItemSelection",
        "QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel",
    },
    "pyside": {
        "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
        "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
        "QtGui.QStringListModel": "QtCore.QStringListModel",
        "QtGui.QItemSelection": "QtCore.QItemSelection",
        "QtGui.QItemSelectionModel": "QtCore.QItemSelectionModel",
        "QtCore.Property": "QtCore.Property",
        "QtCore.Signal": "QtCore.Signal",
        "QtCore.Slot": "QtCore.Slot",

    },
    "pyqt4": {
        "QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
        "QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
        "QtGui.QItemSelection": "QtCore.QItemSelection",
        "QtGui.QStringListModel": "QtCore.QStringListModel",
        "QtGui.QItemSelectionModel": "QtCore.QItemSelectionModel",
        "QtCore.pyqtProperty": "QtCore.Property",
        "QtCore.pyqtSignal": "QtCore.Signal",
        "QtCore.pyqtSlot": "QtCore.Slot",
    }
}

def _apply_site_config():
    try:
        import QtSiteConfig
    except ImportError:
        # If no QtSiteConfig module found, no modifications
        # to _common_members are needed.
        pass
    else:
        # Update _common_members with any changes made by QtSiteConfig
        QtSiteConfig.update_members(_common_members)

def _new_module(name):
    return types.ModuleType(__name__ + "." + name)

def _setup(module, extras):
    """Install common submodules"""

    Qt.__binding__ = module.__name__

    for name in list(_common_members) + extras:
        try:
            submodule = importlib.import_module(
                module.__name__ + "." + name)
        except ImportError:
            continue

        setattr(Qt, "_" + name, submodule)

        if name not in extras:
            # Store reference to original binding,
            # but don't store speciality modules
            # such as uic or QtUiTools
            setattr(Qt, name, _new_module(name))

def _wrapinstance(func, ptr, base=None):
    """Enable implicit cast of pointer to most suitable class

    This behaviour is available in sip per default.

    Based on http://nathanhorne.com/pyqtpyside-wrap-instance

    Usage:
        This mechanism kicks in under these circumstances.
        1. Qt.py is using PySide 1 or 2.
        2. A `base` argument is not provided.

        See :func:`QtCompat.wrapInstance()`

    Arguments:
        func (function): Original function
        ptr (long): Pointer to QObject in memory
        base (QObject, optional): Base class to wrap with. Defaults to QObject,
            which should handle anything.

    """

    assert isinstance(ptr, long), "Argument 'ptr' must be of type <long>"
    assert (base is None) or issubclass(base, Qt.QtCore.QObject), (
        "Argument 'base' must be of type <QObject>")

    if base is None:
        q_object = func(long(ptr), Qt.QtCore.QObject)
        meta_object = q_object.metaObject()
        class_name = meta_object.className()
        super_class_name = meta_object.superClass().className()

        if hasattr(Qt.QtWidgets, class_name):
            base = getattr(Qt.QtWidgets, class_name)

        elif hasattr(Qt.QtWidgets, super_class_name):
            base = getattr(Qt.QtWidgets, super_class_name)

        else:
            base = Qt.QtCore.QObject

    return func(long(ptr), base)

def _reassign_misplaced_members(binding):
    """Parse `_misplaced_members` dict and remap
    values based on the underlying binding.

    :param str binding: Top level binding in _misplaced_members.

    """

    for src, dst in _misplaced_members[binding].items():
        src_module, src_member = src.split(".")
        dst_module, dst_member = dst.split(".")

        try:
            src_object = getattr(Qt, dst_module)
        except AttributeError:
            # Skip reassignment of non-existing members.
            # This can happen if a request was made to
            # rename a member that didn't exist, for example
            # if QtWidgets isn't available on the target platform.
            continue

        dst_value = getattr(getattr(Qt, "_" + src_module), src_member)

        setattr(
            src_object,
            dst_member,
            dst_value
        )

def _pyside2():
    """Initialise PySide2

    These functions serve to test the existence of a binding
    along with set it up in such a way that it aligns with
    the final step; adding members from the original binding
    to Qt.py

    """

    import PySide2 as module
    _setup(module, ["QtUiTools"])

    Qt.__binding_version__ = module.__version__

    try:
        import shiboken2
        Qt.QtCompat.wrapInstance = (
            lambda ptr, base=None: _wrapinstance(
                shiboken2.wrapInstance, ptr, base)
        )
        Qt.QtCompat.getCppPointer = lambda object: \
            shiboken2.getCppPointer(object)[0]

    except ImportError:
        pass  # Optional

    if hasattr(Qt, "_QtUiTools"):
        Qt.QtCompat.loadUi = _loadUi

    if hasattr(Qt, "_QtCore"):
        Qt.__qt_version__ = Qt._QtCore.qVersion()
        Qt.QtCompat.translate = Qt._QtCore.QCoreApplication.translate

    if hasattr(Qt, "_QtWidgets"):
        Qt.QtCompat.setSectionResizeMode = \
            Qt._QtWidgets.QHeaderView.setSectionResizeMode

    _reassign_misplaced_members("pyside2")

def _pyside():
    """Initialise PySide"""

    import PySide as module
    _setup(module, ["QtUiTools"])

    Qt.__binding_version__ = module.__version__

    try:
        import shiboken
        Qt.QtCompat.wrapInstance = (
            lambda ptr, base=None: _wrapinstance(
                shiboken.wrapInstance, ptr, base)
        )
        Qt.QtCompat.getCppPointer = lambda object: \
            shiboken.getCppPointer(object)[0]

    except ImportError:
        pass  # Optional

    if hasattr(Qt, "_QtUiTools"):
        Qt.QtCompat.loadUi = _loadUi

    if hasattr(Qt, "_QtGui"):
        setattr(Qt, "QtWidgets", _new_module("QtWidgets"))
        setattr(Qt, "_QtWidgets", Qt._QtGui)

        Qt.QtCompat.setSectionResizeMode = Qt._QtGui.QHeaderView.setResizeMode

    if hasattr(Qt, "_QtCore"):
        Qt.__qt_version__ = Qt._QtCore.qVersion()
        QCoreApplication = Qt._QtCore.QCoreApplication
        Qt.QtCompat.translate = (
            lambda context, sourceText, disambiguation, n:
            QCoreApplication.translate(
                context,
                sourceText,
                disambiguation,
                QCoreApplication.CodecForTr,
                n
            )
        )

    _reassign_misplaced_members("pyside")

def _pyqt5():
    """Initialise PyQt5"""

    import PyQt5 as module
    _setup(module, ["uic"])

    try:
        import sip
        Qt.QtCompat.wrapInstance = (
            lambda ptr, base=None: _wrapinstance(
                sip.wrapinstance, ptr, base)
        )
        Qt.QtCompat.getCppPointer = lambda object: \
            sip.unwrapinstance(object)

    except ImportError:
        pass  # Optional

    if hasattr(Qt, "_uic"):
        Qt.QtCompat.loadUi = _loadUi

    if hasattr(Qt, "_QtCore"):
        Qt.__binding_version__ = Qt._QtCore.PYQT_VERSION_STR
        Qt.__qt_version__ = Qt._QtCore.QT_VERSION_STR
        Qt.QtCompat.translate = Qt._QtCore.QCoreApplication.translate

    if hasattr(Qt, "_QtWidgets"):
        Qt.QtCompat.setSectionResizeMode = \
            Qt._QtWidgets.QHeaderView.setSectionResizeMode

    _reassign_misplaced_members("pyqt5")

def _pyqt4():
    """Initialise PyQt4"""

    import sip

    # Validation of envivornment variable. Prevents an error if
    # the variable is invalid since it's just a hint.
    try:
        hint = int(QT_SIP_API_HINT)
    except TypeError:
        hint = None  # Variable was None, i.e. not set.
    except ValueError:
        raise ImportError("QT_SIP_API_HINT=%s must be a 1 or 2")

    for api in ("QString",
                "QVariant",
                "QDate",
                "QDateTime",
                "QTextStream",
                "QTime",
                "QUrl"):
        try:
            sip.setapi(api, hint or 2)
        except AttributeError:
            raise ImportError("PyQt4 < 4.6 isn't supported by Qt.py")
        except ValueError:
            actual = sip.getapi(api)
            if not hint:
                raise ImportError("API version already set to %d" % actual)
            else:
                # Having provided a hint indicates a soft constraint, one
                # that doesn't throw an exception.
                sys.stderr.write(
                    "Warning: API '%s' has already been set to %d.\n"
                    % (api, actual)
                )

    import PyQt4 as module
    _setup(module, ["uic"])

    try:
        import sip
        Qt.QtCompat.wrapInstance = (
            lambda ptr, base=None: _wrapinstance(
                sip.wrapinstance, ptr, base)
        )
        Qt.QtCompat.getCppPointer = lambda object: \
            sip.unwrapinstance(object)

    except ImportError:
        pass  # Optional

    if hasattr(Qt, "_uic"):
        Qt.QtCompat.loadUi = _loadUi

    if hasattr(Qt, "_QtGui"):
        setattr(Qt, "QtWidgets", _new_module("QtWidgets"))
        setattr(Qt, "_QtWidgets", Qt._QtGui)

        Qt.QtCompat.setSectionResizeMode = \
            Qt._QtGui.QHeaderView.setResizeMode

    if hasattr(Qt, "_QtCore"):
        Qt.__binding_version__ = Qt._QtCore.PYQT_VERSION_STR
        Qt.__qt_version__ = Qt._QtCore.QT_VERSION_STR

        QCoreApplication = Qt._QtCore.QCoreApplication
        Qt.QtCompat.translate = (
            lambda context, sourceText, disambiguation, n:
            QCoreApplication.translate(
                context,
                sourceText,
                disambiguation,
                QCoreApplication.CodecForTr,
                n)
        )

    _reassign_misplaced_members("pyqt4")

def _none():
    """Internal option (used in installer)"""

    Mock = type("Mock", (), {"__getattr__": lambda Qt, attr: None})

    Qt.__binding__ = "None"
    Qt.__qt_version__ = "0.0.0"
    Qt.__binding_version__ = "0.0.0"
    Qt.QtCompat.loadUi = lambda uifile, baseinstance=None: None
    Qt.QtCompat.setSectionResizeMode = lambda *args, **kwargs: None

    for submodule in _common_members.keys():
        setattr(Qt, submodule, Mock())
        setattr(Qt, "_" + submodule, Mock())

def _log(text):
    if QT_VERBOSE:
        sys.stdout.write(text + "\n")

def _loadUi(uifile, baseinstance=None):
    """Dynamically load a user interface from the given `uifile`

    This function calls `uic.loadUi` if using PyQt bindings,
    else it implements a comparable binding for PySide.

    Documentation:
        http://pyqt.sourceforge.net/Docs/PyQt5/designer.html#PyQt5.uic.loadUi

    Arguments:
        uifile (str): Absolute path to Qt Designer file.
        baseinstance (QWidget): Instantiated QWidget or subclass thereof

    Return:
        baseinstance if `baseinstance` is not `None`. Otherwise
        return the newly created instance of the user interface.

    """
    if hasattr(baseinstance, "layout") and baseinstance.layout():
        message = ("QLayout: Attempting to add Layout to %s which "
                   "already has a layout")
        raise RuntimeError(message % (baseinstance))

    if hasattr(Qt, "_uic"):
        return Qt._uic.loadUi(uifile, baseinstance)

    elif hasattr(Qt, "_QtUiTools"):
        # Implement `PyQt5.uic.loadUi` for PySide(2)

        class _UiLoader(Qt._QtUiTools.QUiLoader):
            """Create the user interface in a base instance.

            Unlike `Qt._QtUiTools.QUiLoader` itself this class does not
            create a new instance of the top-level widget, but creates the user
            interface in an existing instance of the top-level class if needed.

            This mimics the behaviour of `PyQt5.uic.loadUi`.

            """

            def __init__(self, baseinstance):
                super(_UiLoader, self).__init__(baseinstance)
                self.baseinstance = baseinstance

            def load(self, uifile, *args, **kwargs):
                from xml.etree.ElementTree import ElementTree

                # For whatever reason, if this doesn't happen then
                # reading an invalid or non-existing .ui file throws
                # a RuntimeError.
                etree = ElementTree()
                etree.parse(uifile)

                widget = Qt._QtUiTools.QUiLoader.load(
                    self, uifile, *args, **kwargs)

                # Workaround for PySide 1.0.9, see issue #208
                widget.parentWidget()

                return widget

            def createWidget(self, class_name, parent=None, name=""):
                """Called for each widget defined in ui file

                Overridden here to populate `baseinstance` instead.

                """

                if parent is None and self.baseinstance:
                    # Supposed to create the top-level widget,
                    # return the base instance instead
                    return self.baseinstance

                # For some reason, Line is not in the list of available
                # widgets, but works fine, so we have to special case it here.
                if class_name in self.availableWidgets() + ["Line"]:
                    # Create a new widget for child widgets
                    widget = Qt._QtUiTools.QUiLoader.createWidget(self,
                                                                  class_name,
                                                                  parent,
                                                                  name)

                else:
                    raise Exception("Custom widget '%s' not supported"
                                    % class_name)

                if self.baseinstance:
                    # Set an attribute for the new child widget on the base
                    # instance, just like PyQt5.uic.loadUi does.
                    setattr(self.baseinstance, name, widget)

                return widget

        widget = _UiLoader(baseinstance).load(uifile)
        Qt.QtCore.QMetaObject.connectSlotsByName(widget)

        return widget

    else:
        raise NotImplementedError("No implementation available for loadUi")

def _convert(lines):
    """Convert compiled .ui file from PySide2 to Qt.py

    Arguments:
        lines (list): Each line of of .ui file

    Usage:
        >> with open("myui.py") as f:
        ..   lines = _convert(f.readlines())

    """

    def parse(line):
        line = line.replace("from PySide2 import", "from Qt import QtCompat,")
        line = line.replace("QtWidgets.QApplication.translate",
                            "QtCompat.translate")
        return line

    parsed = list()
    for line in lines:
        line = parse(line)
        parsed.append(line)

    return parsed

def _cli(args):
    """Qt.py command-line interface"""
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--convert",
                        help="Path to compiled Python module, e.g. my_ui.py")
    parser.add_argument("--compile",
                        help="Accept raw .ui file and compile with native "
                             "PySide2 compiler.")
    parser.add_argument("--stdout",
                        help="Write to stdout instead of file",
                        action="store_true")
    parser.add_argument("--stdin",
                        help="Read from stdin instead of file",
                        action="store_true")

    args = parser.parse_args(args)

    if args.stdout:
        raise NotImplementedError("--stdout")

    if args.stdin:
        raise NotImplementedError("--stdin")

    if args.compile:
        raise NotImplementedError("--compile")

    if args.convert:
        sys.stdout.write("#\n"
                         "# WARNING: --convert is an ALPHA feature.\n#\n"
                         "# See https://github.com/mottosso/Qt.py/pull/132\n"
                         "# for details.\n"
                         "#\n")

        #
        # ------> Read
        #
        with open(args.convert) as f:
            lines = _convert(f.readlines())

        backup = "%s_backup%s" % os.path.splitext(args.convert)
        sys.stdout.write("Creating \"%s\"..\n" % backup)
        shutil.copy(args.convert, backup)

        #
        # <------ Write
        #
        with open(args.convert, "w") as f:
            f.write("".join(lines))

        sys.stdout.write("Successfully converted \"%s\"\n" % args.convert)

def _install():
    # Default order (customise order and content via QT_PREFERRED_BINDING)
    default_order = ("PySide2", "PyQt5", "PySide", "PyQt4")
    preferred_order = list(
        b for b in QT_PREFERRED_BINDING.split(os.pathsep) if b
    )

    order = preferred_order or default_order

    available = {
        "PySide2": _pyside2,
        "PyQt5": _pyqt5,
        "PySide": _pyside,
        "PyQt4": _pyqt4,
        "None": _none
    }

    _log("Order: '%s'" % "', '".join(order))

    # Allow site-level customization of the available modules.
    _apply_site_config()

    found_binding = False
    for name in order:
        _log("Trying %s" % name)

        try:
            available[name]()
            found_binding = True
            break

        except ImportError as e:
            _log("ImportError: %s" % e)

        except KeyError:
            _log("ImportError: Preferred binding '%s' not found." % name)

    if not found_binding:
        # If not binding were found, throw this error
        raise ImportError("No Qt binding were found.")

    # Install individual members
    for name, members in _common_members.items():
        try:
            their_submodule = getattr(Qt, "_%s" % name)
        except AttributeError:
            continue

        our_submodule = getattr(Qt, name)

        # Enable import *
        __all__.append(name)

        # Enable direct import of submodule,
        # e.g. import Qt.QtCore
        sys.modules[__name__ + "." + name] = our_submodule

        for member in members:
            # Accept that a submodule may miss certain members.
            try:
                their_member = getattr(their_submodule, member)
            except AttributeError:
                _log("'%s.%s' was missing." % (name, member))
                continue

            setattr(our_submodule, member, their_member)

    # Backwards compatibility
    Qt.QtCompat.load_ui = Qt.QtCompat.loadUi

_install()

# Setup Binding Enum states
Qt.IsPySide2 = Qt.__binding__ == 'PySide2'
Qt.IsPyQt5 = Qt.__binding__ == 'PyQt5'
Qt.IsPySide = Qt.__binding__ == 'PySide'
Qt.IsPyQt4 = Qt.__binding__ == 'PyQt4'

"""Augment QtCompat

QtCompat contains wrappers and added functionality
to the original bindings, such as the CLI interface
and otherwise incompatible members between bindings,
such as `QHeaderView.setSectionResizeMode`.

"""

Qt.QtCompat._cli = _cli
Qt.QtCompat._convert = _convert

# Enable command-line interface
if __name__ == "__main__":
    _cli(sys.argv[1:])

# The MIT License (MIT)
#
# Copyright (c) 2016-2017 Marcus Ottosson
#
# 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.
#
# In PySide(2), loadUi does not exist, so we implement it
#
# `_UiLoader` is adapted from the qtpy project, which was further influenced
# by qt-helpers which was released under a 3-clause BSD license which in turn
# is based on a solution at:
#
# - https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8
#
# The License for this code is as follows:
#
# qt-helpers - a common front-end to various Qt modules
#
# Copyright (c) 2015, Chris Beaumont and Thomas Robitaille
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of the Glue project nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Which itself was based on the solution at
#
# https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8
#
# which was released under the MIT license:
#
# Copyright (c) 2011 Sebastian Wiesner <lunaryorn@gmail.com>
# Modifications by Charl Botha <cpbotha@vxlabs.com>
#
# 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.


text:
#pragma once

#include <math.h>
#include <stdint.h>
#include <limits.h>

#include <vector>
#include <algorithm>
#include <iostream>

class Num {
public:
    typedef uint64_t word;

    std::vector<word> words;
    bool neg;

    static word word_mask(){
        return (word)-1;
    }

    static size_t word_bits(){
        return sizeof(word)*CHAR_BIT;
    }

    static word word_half_mask(){
        return word_mask() >> word_bits()/2;
    }

    static word char_to_word(char c){
        switch (c){
            case '0': return 0;
            case '1': return 1;
            case '2': return 2;
            case '3': return 3;
            case '4': return 4;
            case '5': return 5;
            case '6': return 6;
            case '7': return 7;
            case '8': return 8;
            case '9': return 9;
            case 'a': case 'A': return 10;
            case 'b': case 'B': return 11;
            case 'c': case 'C': return 12;
            case 'd': case 'D': return 13;
            case 'e': case 'E': return 14;
            case 'f': case 'F': return 15;
            case 'g': case 'G': return 16;
            case 'h': case 'H': return 17;
            case 'i': case 'I': return 18;
            case 'j': case 'J': return 19;
            case 'k': case 'K': return 20;
            case 'l': case 'L': return 21;
            case 'm': case 'M': return 22;
            case 'n': case 'N': return 23;
            case 'o': case 'O': return 24;
            case 'p': case 'P': return 25;
            case 'q': case 'Q': return 26;
            case 'r': case 'R': return 27;
            case 's': case 'S': return 28;
            case 't': case 'T': return 29;
            case 'u': case 'U': return 30;
            case 'v': case 'V': return 31;
            case 'w': case 'W': return 32;
            case 'x': case 'X': return 33;
            case 'y': case 'Y': return 34;
            case 'z': case 'Z': return 35;
            default: return word_mask();
        }
    }

    static word word_gcd(word a, word b){
        while (1){
            if (a == 0) return b;
            b %= a;
            if (b == 0) return a;
            a %= b;
        }
    }

    Num(): neg(false){}

    Num(size_t n, word w, bool neg = false): words(n, w), neg(neg){}

    Num(const word *a, const word *b, bool neg = false) : words(a, b), neg(neg){
        truncate();
    }

    Num(const Num &a){
        words = a.words;
        neg = a.neg;
    }

    Num& operator = (const Num &a){
        words = a.words;
        neg = a.neg;
        return *this;
    }

    Num(int i): neg(i < 0){
        unsigned u = (i < 0) ? -(unsigned)i : (unsigned)i;
        if (sizeof(u) <= word_bits()){
            if (u > 0) push_back(u);
        }else{
            for (; u; u >>= word_bits()) push_back(u);
        }
    }

    Num(const char *c, word base = 10, char **endptr = NULL): neg(false){
        // read sign
        if (*c == '-'){
            c++;
            neg = true;
        }
        // read digits
        for (;*c; c++){
            mul_word(base);
            word b = char_to_word(*c);
            if (b >= base) break;
            add_word(b);
        }
        if (endptr) *endptr = (char*)c;
    }

    void resize(size_t n){
        words.resize(n);
    }

    void pop_back(){
        words.pop_back();
    }

    void push_back(word b){
        words.push_back(b);
    }

    word& back(){
        return words.back();
    }

    const word& back() const {
        return words.back();
    }

    size_t size() const {
        return words.size();
    }

    word& operator [] (size_t i){
        return words[i];
    }

    const word& operator [] (size_t i) const {
        return words[i];
    }

    Num& set_neg(bool neg){
        this->neg = neg;
        return *this;
    }

    Num& truncate(){
        while (size() > 0 && words.back() == 0) pop_back();
        return *this;
    }

    size_t bitlength() const {
        if (size() == 0) return 0;
        size_t last = size() - 1;
        size_t result = word_bitlength((*this)[last]) + last*word_bits();
        return result;
    }

    size_t count_trailing_zeros() const {
        for (size_t i = 0; i < size(); i++){
            word w = (*this)[i];
            if (w) return word_count_trailing_zeros(w) + i*word_bits();
        }
        return 0;
    }

    static int cmp_abs(const Num &a, const Num &b){
        size_t na = a.size(), nb = b.size();
        if (na != nb){
            return na < nb ? -1 : +1;
        }
        for (size_t i = na; i --> 0;){
            word wa = a[i], wb = b[i];
            if (wa != wb){
                return wa < wb ? -1 : +1;
            }
        }
        return 0;
    }

    static int cmp(const Num &a, const Num &b){
        if (a.size() == 0 && b.size() == 0) return 0;
        if (!a.neg && !b.neg) return +cmp_abs(a, b);
        if ( a.neg &&  b.neg) return -cmp_abs(a, b);
        return a.neg && !b.neg ? -1 : +1;
    }

    static size_t word_bitlength(word a){
        for (int i = word_bits() - 1; i >= 0; i--) if ((a >> i) & 1) return i+1;
        return 0;
    }

    static size_t word_count_trailing_zeros(word a){
        for (int i = 0; i < (int)word_bits(); i++) if ((a >> i) & 1) return i;
        return word_bits();
    }

    static word add_carry(word *a, word b){
        return (*a += b) < b;
    }

    static word sub_carry(word *a, word b){
        word tmp = *a;
        return (*a = tmp - b) > tmp;
    }

    static word word_mul_hi(word a, word b){
        size_t n = word_bits()/2;
        word a_hi = a >> n;
        word a_lo = a & word_half_mask();
        word b_hi = b >> n;
        word b_lo = b & word_half_mask();
        word tmp = ((a_lo*b_lo) >> n) + a_hi*b_lo;
        tmp = (tmp >> n) + ((a_lo*b_hi + (tmp & word_half_mask())) >> n);
        return tmp + a_hi*b_hi;
    }

    static Num& add_unsigned_overwrite(Num &a, const Num &b){
        size_t i, na = a.size(), nb = b.size(), n = std::max(na, nb);
        a.resize(n);
        word carry = 0;
        for (i = 0; i < nb; i++){
            carry  = add_carry(&a[i], carry);
            carry += add_carry(&a[i], b[i]);
        }
        for (; i < n && carry; i++) carry = add_carry(&a[i], carry);
        if (carry) a.push_back(carry);
        return a.truncate();
    }

    static Num& sub_unsigned_overwrite(Num &a, const Num &b){
        //assert(cmp_abs(a, b) >= 0);
        size_t i, na = a.size(), nb = b.size();
        word carry = 0;
        for (i = 0; i < nb; i++){
            carry  = sub_carry(&a[i], carry);
            carry += sub_carry(&a[i], b[i]);
        }
        for (; i < na && carry; i++) carry = sub_carry(&a[i], carry);
        //assert(!carry);
        return a.truncate();
    }

    static Num mul_long(const Num &a, const Num &b){
        size_t na = a.size(), nb = b.size(), nc = na + nb + 1;
        Num c(nc, 0, a.neg ^ b.neg), carries(nc, 0);
        for (size_t ia = 0; ia < na; ia++){
            for (size_t ib = 0; ib < nb; ib++){
                size_t i = ia + ib, j = i + 1;
                // WARNING: Might overflow if word size is chosen too small
                carries[i + 1] += add_carry(&c[i], a[ia] * b[ib]);
                carries[j + 1] += add_carry(&c[j], word_mul_hi(a[ia], b[ib]));
            }
        }
        return add_unsigned_overwrite(c, carries).truncate();
    }

    static Num mul_karatsuba(const Num &a, const Num &b){
        size_t na = a.size(), nb = b.size(), n = std::max(na, nb), m2 = n/2 + (n & 1);
        Num a_parts[2], b_parts[2];
        split(a, a_parts, 2, m2);
        split(b, b_parts, 2, m2);
        m2 *= word_bits();
        Num z0 = a_parts[0] * b_parts[0];
        Num z1 = (a_parts[0] + a_parts[1]) * (b_parts[0] + b_parts[1]);
        Num z2 = a_parts[1] * b_parts[1];
        Num result = z2;
        result <<= m2;
        result += z1 - z2 - z0;
        result <<= m2;
        result += z0;
        return result;
    }

    static Num mul(const Num &a, const Num &b){
        size_t karatsuba_threshold = 20;
        if (a.size() > karatsuba_threshold && b.size() > karatsuba_threshold){
            return mul_karatsuba(a, b);
        }
        return mul_long(a, b);
    }

    static Num add_signed(const Num &a, bool a_neg, const Num &b, bool b_neg){
        if (a_neg == b_neg) return add_unsigned(a, b).set_neg(a_neg);
        if (cmp_abs(a, b) >= 0) return sub_unsigned(a, b).set_neg(a_neg);
        return sub_unsigned(b, a).set_neg(b_neg);
    }

    Num& operator >>= (size_t n_bits){
        if (n_bits == 0) return *this;
        size_t n_words = n_bits / word_bits();
        if (n_words >= size()){
            resize(0);
            return *this;
        }
        n_bits %= word_bits();
        if (n_bits == 0){
            for (size_t i = 0; i < size() - n_words; i++){
                (*this)[i] = (*this)[i + n_words];
            }
        }else{
            word hi, lo = (*this)[n_words];
            for (size_t i = 0; i < size() - n_words - 1; i++){
                hi = (*this)[i + n_words + 1];
                (*this)[i] = (hi << (word_bits() - n_bits)) | (lo >> n_bits);
                lo = hi;
            }
            (*this)[size() - n_words - 1] = lo >> n_bits;
        }
        resize(size() - n_words);
        return truncate();
    }

    Num& operator <<= (size_t n_bits){
        if (n_bits == 0) return *this;
        size_t n_words = n_bits / word_bits();
        n_bits %= word_bits();
        size_t old_size = size();
        size_t n = old_size + n_words + (n_bits != 0);
        resize(n);
        if (n_bits == 0){
            for (size_t i = n; i --> n_words;){
                (*this)[i] = (*this)[i - n_words];
            }
        }else{
            word lo, hi = 0;
            for (size_t i = n - 1; i > n_words; i--){
                lo = (*this)[i - n_words - 1];
                (*this)[i] = (hi << n_bits) | (lo >> (word_bits() - n_bits));
                hi = lo;
            }
            (*this)[n_words] = hi << n_bits;
        }
        for (size_t i = 0; i < n_words; i++) (*this)[i] = 0;
        return truncate();
    }

    static void div_mod(const Num &numerator, Num denominator, Num &quotient, Num &remainder){
        quotient = 0;
        remainder = numerator;
        if (cmp_abs(remainder, denominator) >= 0){
            int n = numerator.bitlength() - denominator.bitlength();
            denominator <<= n;
            for (; n >= 0; n--){
                if (cmp_abs(remainder, denominator) >= 0){
                    sub_unsigned_overwrite(remainder, denominator);
                    quotient.set_bit(n);
                }
                denominator >>= 1;
            }
        }
        quotient.set_neg(numerator.neg ^ denominator.neg);
        remainder.set_neg(numerator.neg);
    }

    static void div_mod_half_word(const Num &numerator, word denominator, Num &quotient, word &remainder){
        remainder = 0;
        Num dst(numerator.size(), 0);

        for (size_t i = numerator.size(); i --> 0;){
            word dst_word = 0;
            word src_word = numerator[i];
            word parts[2];
            parts[0] = src_word >> word_bits()/2;
            parts[1] = src_word & word_half_mask();

            for (size_t j = 0; j < 2; j++){
                remainder <<= word_bits()/2;
                remainder |= parts[j];

                word div_word = remainder / denominator;
                word mod_word = remainder % denominator;
                remainder = mod_word;

                dst_word <<= word_bits()/2;
                dst_word |= div_word;
            }

            dst[i] = dst_word;
        }

        quotient = dst.truncate().set_neg(numerator.neg);
    }

    static void split(const Num &a, Num *parts, size_t n_parts, size_t n){
        size_t i = 0;
        for (size_t k = 0; k < n_parts; k++){
            Num &part = parts[k];
            part.resize(n);
            for (size_t j = 0; j < n && i < a.size(); j++) part[j] = a[i++];
            part = part.truncate();
        }
    }

    static Num div(const Num &numerator, const Num& denominator){
        Num quotient, remainder;
        div_mod(numerator, denominator, quotient, remainder);
        return quotient;
    }

    static Num mod(const Num &numerator, const Num& denominator){
        Num quotient, remainder;
        div_mod(numerator, denominator, quotient, remainder);
        return remainder;
    }

    static Num add_unsigned(const Num &a, const Num &b){
        Num result(a);
        return add_unsigned_overwrite(result, b);
    }

    static Num sub_unsigned(const Num &a, const Num &b){
        Num result(a);
        return sub_unsigned_overwrite(result, b);
    }

    static Num add(const Num &a, const Num &b){
        Num result = add_signed(a, a.neg, b, b.neg);
        return result;
    }

    static Num sub(const Num &a, const Num &b){
        Num result = add_signed(a, a.neg, b, !b.neg);
        return result;
    }

    static Num gcd(const Num &a0, const Num &b0){

        if (a0.size() == 1 && b0.size() == 1){
            return Num(1, word_gcd(a0[0], b0[0]));
        }

        Num a(a0), b(b0);
        a.neg = b.neg = false;

        if (a.size() == 0) return b0;
        if (b.size() == 0) return a0;

        size_t n = a.count_trailing_zeros();
        size_t m = b.count_trailing_zeros();
        if (n > m) {
            std::swap(n, m);
            a.words.swap(b.words);
        }

        a >>= n;
        b >>= n;

        do {
            b >>= b.count_trailing_zeros();
            if (cmp_abs(a, b) > 0) a.words.swap(b.words);
            sub_unsigned_overwrite(b, a);
        } while (b.size() > 0);

        a <<= n;

        return a;
    }

    typedef void (*random_func)(uint8_t *bytes, size_t n_bytes);

    static Num random_bits(size_t n_bits, random_func func){
        if (n_bits == 0) return 0;
        size_t partial_bits = n_bits % word_bits();
        size_t n_words = n_bits / word_bits() + (partial_bits > 0);
        size_t n_bytes = n_words*sizeof(word);
        Num result(n_words, 0);
        uint8_t *bytes = (uint8_t*)&result[0];
        func(bytes, n_bytes);
        if (partial_bits){
            size_t too_many_bits = word_bits() - partial_bits;
            result.back() >>= too_many_bits;
        }
        return result;
    }

    static Num random_inclusive(const Num &inclusive, random_func func){
        size_t n_bits = inclusive.bitlength();
        while (true){
            Num result = random_bits(n_bits, func);
            if (result <= inclusive) return result;
        }
    }

    static Num random_exclusive(const Num &exclusive, random_func func){
        size_t n_bits = exclusive.bitlength();
        while (true){
            Num result = random_bits(n_bits, func);
            if (result < exclusive) return result;
        }
    }

    static Num random_second_exclusive(const Num &inclusive_min_val, const Num &exclusive_max_val, random_func func){
        return inclusive_min_val + random_exclusive(exclusive_max_val - inclusive_min_val, func);
    }

    static Num random_both_inclusive(const Num &inclusive_min_val, const Num &inclusive_max_val, random_func func){
        return inclusive_min_val + random_inclusive(inclusive_max_val - inclusive_min_val, func);
    }

    Num& set_bit(size_t i){
        size_t i_word = i / word_bits();
        size_t i_bit =  i % word_bits();
        if (size() <= i_word) resize(i_word + 1);
        (*this)[i_word] |= ((word)1) << i_bit;
        return *this;
    }

    word get_bit(size_t i) const {
        size_t i_word = i / word_bits();
        size_t i_bit =  i % word_bits();
        if (i_word >= size()) return 0;
        return ((*this)[i_word] >> i_bit) & 1;
    }

    void clr_bit(size_t i){
        size_t i_word = i / word_bits();
        size_t i_bit =  i % word_bits();
        if (i_word >= size()) return;
        word mask = 1;
        mask <<= i_bit;
        (*this)[i_word] &= ~mask;
    }

    Num& mul_word(word b){
        word carry = 0;
        for (size_t i = 0; i < size(); i++){
            word a = (*this)[i];
            word tmp = a * b;
            carry = add_carry(&tmp, carry);
            carry += word_mul_hi(a, b);
            (*this)[i] = tmp;
        }
        if (carry) push_back(carry);
        return truncate();
    }

    Num& add_word(word carry, size_t i0 = 0){
        if (i0 >= size()) resize(i0 + 1);
        for (size_t i = i0; i < size() && carry; i++){
            carry = add_carry(&(*this)[i], carry);
        }
        if (carry) push_back(carry);
        return truncate();
    }

    void print(
        std::vector<char> &text,
        word base = 10,
        const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
    ) const {
        if (size() == 0){
            text.push_back('0');
        }else{
            Num tmp(*this);
            while (tmp.size() > 0){
                word remainder;
                div_mod_half_word(tmp, base, tmp, remainder);
                text.push_back(alphabet[remainder]);
            }
            if (neg) text.push_back('-');
            std::reverse(text.begin(), text.end());
        }
        text.push_back('\0');
    }

    friend std::ostream& operator << (std::ostream& out, const Num &num){
        std::vector<char> tmp;
        num.print(tmp);
        out << &tmp[0];
        return out;
    }

    double to_double() const {
        if (size() == 0) return 0.0;
        double d = 0.0, base = ::pow(2.0, word_bits());
        for (size_t i = size(); i --> 0;) d = d * base + (*this)[i];
        return neg ? -d : d;
    }

    bool can_convert_to_int(int *result){
        if (*this < Num(INT_MIN) || *this > Num(INT_MAX)) return false;

        unsigned temp = 0;

        if (word_bits() >= sizeof(temp)*CHAR_BIT){
            if (words.size() > 0){
                temp = (*this)[0];
            }
        }else{
            for (size_t i = words.size(); i --> 0;){
                temp <<= word_bits();
                temp += (*this)[i];
            }
        }

        *result = neg ? -temp : temp;

        return true;
    }

    Num pow(size_t exponent) const {
        Num result(1), p(*this);
        for (; exponent; exponent >>= 1){
            if (exponent & 1){
                result = result * p;
                exponent--;
            }
            p = p*p;
        }
        return result;
    }

    Num mod_pow(Num exponent, const Num &modulus) const {
        Num result(1), base = (*this) % modulus;
        for (; exponent.size() > 0; exponent >>= 1){
            if (exponent.get_bit(0)){
                result = (result * base) % modulus;
            }
            base = (base * base) % modulus;
        }
        return result;
    }

    Num sqrt() const {
        Num n = *this;
        int bit = bitlength();
        if (bit & 1) bit ^= 1;
        Num result = 0;
        for (; bit >= 0; bit -= 2){
            Num tmp = result;
            tmp.set_bit(bit);
            if (n >= tmp){
                n -= tmp;
                result.set_bit(bit + 1);
            }
            result >>= 1;
        }
        return result;
    }

    Num& operator ++(){
        add_word(1);
        return *this;
    }

    Num& operator += (const Num &b){ return *this = add(*this, b); }
    Num& operator -= (const Num &b){ return *this = sub(*this, b); }
    Num& operator *= (const Num &b){ return *this = mul(*this, b); }
    Num& operator /= (const Num &b){ return *this = div(*this, b); }
    Num& operator %= (const Num &b){ return *this = mod(*this, b); }

    bool operator == (const Num &b) const { return cmp(*this, b) == 0; }
    bool operator != (const Num &b) const { return cmp(*this, b) != 0; }
    bool operator <= (const Num &b) const { return cmp(*this, b) <= 0; }
    bool operator >= (const Num &b) const { return cmp(*this, b) >= 0; }
    bool operator <  (const Num &b) const { return cmp(*this, b) <  0; }
    bool operator >  (const Num &b) const { return cmp(*this, b) >  0; }

    Num operator + (const Num &b) const { return add(*this, b); }
    Num operator - (const Num &b) const { return sub(*this, b); }
    Num operator * (const Num &b) const { return mul(*this, b); }
    Num operator / (const Num &b) const { return div(*this, b); }
    Num operator % (const Num &b) const { return mod(*this, b); }
    Num operator - (            ) const { return Num(*this).set_neg(!neg); }

    Num operator >> (size_t n_bits) const { return Num(*this) >>= n_bits; }
    Num operator << (size_t n_bits) const { return Num(*this) <<= n_bits; }
};

mime_type: text/plain


text:
#include "num.hpp"
#include "rat.hpp"
#include <assert.h>
#include <stdio.h>

int cmp(int a, int b){
    if (a == b) return 0;
    return a < b ? -1 : +1;
}

int cmp_abs(int a, int b){
    return cmp(std::abs(a), std::abs(b));
}

int gcd(int a, int b){
    a = std::abs(a);
    b = std::abs(b);
    while (1){
        if (b == 0) return a;
        a %= b;
        if (a == 0) return b;
        b %= a;
    }
}

void calculate_pqt(const Num &a, const Num &b, Num &P, Num &Q, Num &T){
    if (a + 1 == b){
        if (a.size()){
            P = (a*2 - 1)*(a*6 - 5)*(a*6 - 1);
            Q = a*a*a*"10939058860032000";
        }else{
            P = 1;
            Q = 1;
        }
        T = P * (a*545140134 + 13591409);
        if (a.get_bit(0)) T = -T;
    }else{
        Num P1, Q1, T1, P2, Q2, T2, m = (a + b) >> 1;
        calculate_pqt(a, m, P1, Q1, T1);
        calculate_pqt(m, b, P2, Q2, T2);
        P = P1 * P2;
        Q = Q1 * Q2;
        T = Q2 * T1 + P1 * T2;
    }
}

Num calculate_pi(size_t n_digits){
    double digits_per_iteration = 14.1816474627;
    Num iterations = n_digits / digits_per_iteration + 1;
    iterations += 3;
    Num P, Q, T;
    calculate_pqt(0, iterations, P, Q, T);
    Num pi = (Num(100).pow(n_digits)*10005).sqrt()*Q*426880 / T;
    return pi;
}

Rat calculate_e(int iterations = 10){
    Num x = 2 + 4*iterations;
    Rat result = x + 4;
    for (; x >= 6; x -= 4) result = result.inv() + x;
    return (result.inv() + 1).inv()*2 + 1;
}

void test_int_conversion(){
    for (int i = 1; i <= 1024; i++){
        int result = 666;

        assert(!(Num(INT_MAX) + i).can_convert_to_int(&result));
        assert(!(Num(INT_MIN) - i).can_convert_to_int(&result));

        assert((Num(INT_MAX) - i).can_convert_to_int(&result) && (INT_MAX - i) == result);
        assert((Num(INT_MIN) + i).can_convert_to_int(&result) && (INT_MIN + i) == result);

        assert(Num(i).can_convert_to_int(&result) && result == i);
        assert(Num(-i).can_convert_to_int(&result) && result == -i);
    }

    int result = 666;
    assert(Num(0).can_convert_to_int(&result) && result == 0);
    assert(Num(INT_MAX).can_convert_to_int(&result) && result == INT_MAX);
    assert(Num(INT_MIN).can_convert_to_int(&result) && result == INT_MIN);
}

void test_leading_zeros(){
    // Tests for https://github.com/983/Num/issues/3
    Num::word a_words[3] = {6 * 7, 0, 0};
    Num::word b_words[3] = {6, 0, 0};

    Num a(a_words, a_words + 3);
    Num b(b_words, b_words + 3);

    assert(a / b == 7);

    a = Num("0000000000000000000000000000000013489961122943955613306345758787541999851062335863782808385326197845909249632");
    b = Num("0000000000000000000000000280032787018263786953141954571555252043");
    Num c("48172791716936124370501454722037223916");
    assert(a / b == c);
}

int main(){
    test_int_conversion();
    test_leading_zeros();

    Num pi = calculate_pi(1000);
    assert(pi == "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989");

    std::vector<char> c;
    pi.print(c);
    printf("pi to %i digits:\n%c.%s\n", int(c.size()) - 2, c[0], &c[1]);

    assert(pi == Num(&c[0]));

    Rat e = calculate_e();
    printf("\n15 digits of e: %.15f\n", e.to_double());
    double d = e.to_double() - 2.718281828459045;
    double eps = 1e-15;
    assert(-eps < d && d < eps);

    Rat r(1337, 191);
    r.print(c);
    assert(r == 7);

    assert(Num(666).mod_pow(1337, 1234) == 816);

    assert(Num(666).mod_pow(0, 1000) == 1);

    int n = 100;
    for (int a = -n; a <= n; a++){
        for (int b = -n; b <= n; b++){
            assert(cmp_abs(a, b) == Num::cmp_abs(Num(a), Num(b)));
            assert(cmp    (a, b) == Num::cmp(Num(a), Num(b)));
            assert((Num(a) == Num(b)) == (a == b));
            assert((Num(a) != Num(b)) == (a != b));
            assert((Num(a) <= Num(b)) == (a <= b));
            assert((Num(a) >= Num(b)) == (a >= b));
            assert((Num(a) <  Num(b)) == (a <  b));
            assert((Num(a) >  Num(b)) == (a >  b));
            assert((Num(a) +  Num(b)) == (a +  b));
            assert((Num(a) -  Num(b)) == (a -  b));
            assert((Num(a) *  Num(b)) == (a *  b));
            if (a >= 0 && b >= 0){
                assert(Num(a) >> b % 18 == Num(a >> b % 18));
                assert(Num(a) << b % 18 == Num(a << b % 18));
            }
            if (b != 0){
                assert((Num(a) /  Num(b)) == (a /  b));
                assert((Num(a) %  Num(b)) == (a %  b));
                if (a != 0) assert(Num::gcd(a, b) == gcd(a, b));
            }
            if (b > 1 && std::abs(b) <= Num::word_half_mask()){
                Num tmp(a);
                Num::word remainder;
                Num::div_mod_half_word(tmp, b, tmp, remainder);
                assert(remainder == std::abs(a%b));
                assert(tmp == Num(a/b));
            }
        }
    }

    for (size_t n = 2; n < 100; n++){
        Num a(n, Num::word_mask());
        Num c = a * a;
        size_t m = c.size();
        assert(c[0] == 1);
        for (size_t i = 1; i < m/2; i++) assert(c[i] == 0);
        assert(c[m/2] == Num::word_mask() - 1);
        for (size_t i = m/2 + 1; i < m; i++) assert(c[i] == Num::word_mask());
    }

    return 0;
}


text:
#pragma once

#include "num.hpp"

struct Rat {
    Num num, den;

    Rat(){}

    Rat(int num): num(num), den(1){}

    Rat(const Num &num): num(num), den(1){}

    Rat(const Num &num, const Num &den): num(num), den(den){
        reduce();
    }

    void reduce(){
        Num a = Num::gcd(num, den);
        if (a != 1){
            num /= a;
            den /= a;
        }
    }

    Rat inv() const {
        return Rat(den, num);
    }

    static Rat add(const Rat &a, const Rat &b){
        return Rat(a.num * b.den + a.den*b.num, a.den * b.den);
    }

    static Rat sub(const Rat &a, const Rat &b){
        return Rat(a.num * b.den - a.den*b.num, a.den * b.den);
    }

    static Rat mul(const Rat &a, const Rat &b){
        return Rat(a.num * b.num, a.den * b.den);
    }

    static Rat div(const Rat &a, const Rat &b){
        return Rat(a.num * b.den, a.den * b.num);
    }

    static int cmp(const Rat &a, const Rat &b){
        int result = Num::cmp(a.num * b.den, b.num * a.den);
        return b.den != a.den ? -result : result;
    }

    double to_double() const {
        return num.to_double() / den.to_double();
    }

    void print(std::vector<char> &c){
        num.print(c);
        c.back() = '/';
        den.print(c);
    }

    Rat& operator += (const Rat &b){ return *this = add(*this, b); }
    Rat& operator -= (const Rat &b){ return *this = sub(*this, b); }
    Rat& operator *= (const Rat &b){ return *this = mul(*this, b); }
    Rat& operator /= (const Rat &b){ return *this = div(*this, b); }

    bool operator == (const Rat &b) const { return cmp(*this, b) == 0; }
    bool operator != (const Rat &b) const { return cmp(*this, b) != 0; }
    bool operator <= (const Rat &b) const { return cmp(*this, b) <= 0; }
    bool operator >= (const Rat &b) const { return cmp(*this, b) >= 0; }
    bool operator <  (const Rat &b) const { return cmp(*this, b) <  0; }
    bool operator >  (const Rat &b) const { return cmp(*this, b) >  0; }

    Rat operator + (const Rat &b) const { return add(*this, b); }
    Rat operator - (const Rat &b) const { return sub(*this, b); }
    Rat operator * (const Rat &b) const { return mul(*this, b); }
    Rat operator / (const Rat &b) const { return div(*this, b); }
    Rat operator - (            ) const { return Rat(-num, den); }
};


text:
# Num
Single file header only C++ implementation of BigInteger / BigNum / unlimited size integers and rational numbers

### Supported operations on `Num` type:

Artithmetic:
`+, -, *, /, +=, -=, *=, /=, %=`

Comparison:
`==, !=, <=, >=, <, >`

Bit ops:
`get_bit, set_bit, clr_bit`

Shifts:
`<<, >>, <<=, >>=`

Fancy stuff:
`gcd, sqrt, pow, mod_pow, div_mod`

Base conversion:
```cpp
Num a("539", 16);

std::vector<char> c;
a.print(c, 2);
puts(&c[0]); // 10100111001
```

For more examples, e.g. calculating digits of `Pi` and `e`, see `tests.cpp`.


text:
This resource was made by developers and hackers alike. We appreciate and recognize [all contributors](https://github.com/narkopolo/awesome-password-cracking/graphs/contributors).

# Contribution Guidelines

- **To add to the list:** Submit a pull request
- **To remove from the list:** Open an issue

`awesome-password-cracking` is a curated list of awesome tools, research, papers and other projects related to password cracking and password security.

- List items should be sorted *alphabetically*.
- Each item should be limited to one link
- The link should be the name of the package or project
- Descriptions should be clear, concise, and non-promotional
- Descriptions should follow the link, on the same line

Please contribute links to packages/projects you have used or are familiar with. This will help ensure high-quality entries.

## Quality standard

To stay on the list, package repositories should adhere to these quality standards:

- Generally useful to the community
- Functional
- Actively maintained (even if that just means acknowledging open issues when they arise)
- Stable, or progressing toward stable
- Solves a real problem


text:
# Awesome Password Cracking	 [![Awesome](https://awesome.re/badge.svg)](https://awesome.re)

In cryptanalysis and computer security, password cracking is the process of recovering passwords from data that has been stored in or transmitted by a computer system in scrambled form. A common approach ([brute-force attack](https://en.wikipedia.org/wiki/Brute-force_attack)) is to repeatedly try guesses for the password and to check them against an available cryptographic hash of the password.

This is a curated list of awesome tools, research, papers and other projects related to password cracking and password security by [@n0kovo@infosec.exchange](https://infosec.exchange/@n0kovo/?l).

Read [CONTRIBUTING.md](https://github.com/narkopolo/awesome-password-cracking/blob/main/CONTRIBUTING.md) before contributing! In short:

- List is alphabetically sorted
- If in doubt, use [awesome-lint](https://github.com/sindresorhus/awesome-lint)
- If you think an item shouldn't be here [open an issue](https://github.com/narkopolo/awesome-password-cracking/issues/new)

## Contents

- [Books](#books)
- [Cloud](#cloud)
- [Conversion](#conversion)
- [Hashcat](#hashcat)
  - [Automation](#automation)
  - [Distributed cracking](#distributed-cracking)
  - [Rules](#rules)
  - [Rule tools](#rule-tools)
  - [Web interfaces](#web-interfaces)
- [John the Ripper](#john-the-ripper)
- [Misc](#misc)
  - [Notable People](#notable-people)
- [Websites](#websites)
  - [Communities](#communities)
  - [Lookup services](#lookup-services)
- [Wordlist tools](#wordlist-tools)
  - [Analysis](#analysis)
  - [Generation/Manipulation](#generationmanipulation)
- [Wordlists](#wordlists)
  - [Laguage specific](#laguage-specific)
  - [Other](#other)
- [Specific file formats](#specific-file-formats)
  - [PDF](#pdf)
  - [PEM](#pem)
  - [JKS](#jks)
  - [ZIP](#zip)
- [Artificial Intelligence](#artificial-intelligence)
- [Research](#research)
  - [Articles and Blog Posts](#articles-and-blog-posts)
  - [Papers](#papers)
  - [Talks](#talks)

## Books
- [Hash Crack: Password Cracking Manual (v3)](https://www.amazon.com/-/en/Joshua-Picolet/dp/1793458618) - Password Cracking Manual v3 is an expanded reference guide for password recovery (cracking) methods, tools, and analysis techniques.

## Cloud
- [Cloud_crack](https://github.com/lordsaibat/Cloud_crack) - Crack passwords using Terraform and AWS.
- [Cloudcat](https://github.com/stormfleet/cloudcat) - A script to automate the creation of cloud infrastructure for hash cracking.
- [Cloudstomp](https://github.com/Fmstrat/cloudstomp) - Automated deployment of instances on EC2 via plugin for high CPU/GPU applications at the lowest price.
- [Cloudtopolis](https://github.com/JoelGMSec/Cloudtopolis) - A tool that facilitates the installation and provisioning of Hashtopolis on the Google Cloud Shell platform, quickly and completely unattended (and also, free!).
- [NPK](https://github.com/c6fc/npk) - NPK is a distributed hash-cracking platform built entirely of serverless components in AWS including Cognito, DynamoDB, and S3.
- [Penglab](https://github.com/mxrch/penglab) - Abuse of Google Colab for cracking hashes.
- [Rook](https://github.com/JumpsecLabs/Rook) - Automates the creation of AWS p3 instances for use in GPU-based password cracking.

## Conversion
- [7z2hashcat](https://github.com/philsmd/7z2hashcat) - Extract information from password-protected .7z archives (and .sfx files) such that you can crack these "hashes" with hashcat.
- [MacinHash](https://github.com/jmagers/MacinHash) - Convert macOS plist password file to hash file for password crackers.
- [NetNTLM-Hashcat](https://github.com/ins1gn1a/NetNTLM-Hashcat) - Converts John The Ripper/Cain format hashes (singular, or in bulk) to HashCat compatible hash format.
- [Rubeus-to-Hashcat](https://github.com/PwnDexter/Rubeus-to-Hashcat) - Converts / formats Rubeus kerberoasting output into hashcat readable format.
- [WINHELLO2hashcat](https://github.com/Banaanhangwagen/WINHELLO2hashcat) - With this tool one can extract the "hash" from a WINDOWS HELLO PIN. This hash can be cracked with Hashcat.
- [bitwarden2hashcat](https://github.com/0x6470/bitwarden2hashcat) - A tool that converts Bitwarden's data into a hashcat-suitable hash.
- [hc\_to\_7z](https://github.com/philsmd/hc_to_7z) - Convert 7-Zip hashcat hashes back to 7z archives.
- [hcxtools](https://github.com/ZerBea/hcxtools) - Portable solution for conversion of cap/pcap/pcapng (gz compressed) WiFi dump files to hashcat formats.
- [itunes_backup2hashcat](https://github.com/philsmd/itunes_backup2hashcat) - Extract the information needed from the Manifest.plist files to convert it to hashes compatible with hashcat.
- [mongodb2hashcat](https://github.com/philsmd/mongodb2hashcat) - Extract hashes from the MongoDB database server to a hash format that hashcat accepts: -m 24100 (SCRAM-SHA-1) or -m 24200 (SCRAM-SHA-256).

## Hashcat
*[Hashcat](https://github.com/hashcat/hashcat) is the "World's fastest and most advanced password recovery utility." The following are projects directly related to Hashcat in one way or another.*

- [Autocrack](https://github.com/pry0cc/autocrack) - A set of client and server tools for automatically, and lightly automatically cracking hashes.
- [docker-hashcat](https://github.com/dizcza/docker-hashcat) - Latest hashcat docker for Ubuntu 18.04 CUDA, OpenCL, and POCL.
- [hashcat.launcher](https://github.com/s77rt/hashcat.launcher) - Hashcat.launcher is a cross-platform GUI app that run and control hashcat.
- [Hashcat-Stuffs](https://github.com/xfox64x/Hashcat-Stuffs) - Collection of hashcat lists and things.
- [hashcat-utils](https://github.com/hashcat/hashcat-utils/) - Small utilities that are useful in advanced password cracking.
- [Hashfilter](https://github.com/bharshbarger/Hashfilter) - Read a hashcat potfile and parse different types into a sqlite database.
- [known_hosts-hashcat](https://github.com/chris408/known_hosts-hashcat) - A guide and tool for cracking ssh known_hosts files with hashcat.
- [pyhashcat](https://github.com/f0cker/pyhashcat) - Python C API binding to libhashcat.

### Automation
- [autocrack](https://github.com/timbo05sec/autocrack) - Hashcat wrapper to help automate the cracking process.
- [hat](https://github.com/sp00ks-git/hat) - An Automated Hashcat Tool for common wordlists and rules to speed up the process of cracking hashes during engagements.
- [hate_crack](https://github.com/trustedsec/hate_crack) - A tool for automating cracking methodologies through Hashcat from the TrustedSec team.
- [Naive hashcat](https://github.com/brannondorsey/naive-hashcat) - Naive hashcat is a plug-and-play script that is pre-configured with naive, emperically-tested, "good enough" parameters/attack types.

### Distributed cracking
- [CrackLord](https://github.com/jmmcatee/cracklord) - Queue and resource system for cracking passwords.
- [fitcrack](https://github.com/nesfit/fitcrack) - A hashcat-based distributed password cracking system.
- [Hashtopolis](https://github.com/hashtopolis/server) - A multi-platform client-server tool for distributing hashcat tasks to multiple computers.
- [HashtopoloCLI](https://github.com/jakewnuk/HashtopoCLI) - CLI tool for Hashtopolis API incorporating some of the API functionality into a dynamic Python wrapper.
- [Kraken](https://github.com/arcaneiceman/kraken) - A multi-platform distributed brute-force password cracking system.

### Rules
- [clem9669 rules](https://github.com/clem9669/hashcat-rule) - Rule for hashcat or john.
- [hashcat rules collection](https://github.com/narkopolo/hashcat-rules-collection) - Probably the largest collection of hashcat rules out there.
- [Hob0Rules](https://github.com/praetorian-inc/Hob0Rules) - Password cracking rules for Hashcat based on statistics and industry patterns.
- [Kaonashi](https://github.com/kaonashi-passwords/Kaonashi) - Wordlist, rules and masks from Kaonashi project (RootedCON 2019).
- [nsa-rules](https://github.com/NSAKEY/nsa-rules) - Password cracking rules and masks for hashcat generated from cracked passwords.
- [nyxgeek-rules](https://github.com/nyxgeek/nyxgeek-rules) - Custom password cracking rules for Hashcat and John the Ripper.
- [OneRuleToRuleThemAll](https://github.com/NotSoSecure/password_cracking_rules) - "One rule to crack all passwords. or atleast we hope so."
- [OneRuleToRuleThemStill](https://github.com/stealthsploit/OneRuleToRuleThemStill) - "A revamped and updated version of my original OneRuleToRuleThemAll hashcat rule."
- [pantagrule](https://github.com/rarecoil/pantagrule) - Large hashcat rulesets generated from real-world compromised passwords.
- [squid rules](https://github.com/jakewnuk/HIBP-578M) - Hashcat rules ordered by effectiveness from testing HIBPv7.

### Rule tools
- [duprule](https://github.com/mhasbini/duprule) - Detect & filter duplicate hashcat rules.
- [ruleprocessorY](https://github.com/TheWorkingDeveloper/ruleprocessorY) - A next-gen Rule processor with complex multibyte character support built to support Hashcat.

### Web interfaces
- [crackerjack](https://github.com/ctxis/crackerjack) - CrackerJack is a Web GUI for Hashcat developed in Python.
- [CrackQ](https://github.com/f0cker/crackq) - A Python Hashcat cracking queue system.
- [hashpass](https://github.com/dj-zombie/hashpass) - Hash cracking WebApp & Server for hashcat.
- [Hashview](https://github.com/hashview/hashview) - A web front-end for password cracking and analytics.
- [Wavecrack](https://github.com/wavestone-cdt/wavecrack) - Wavestone's web interface for password cracking with hashcat.
- [WebHashCat](https://github.com/hegusung/WebHashcat) - WebHashcat is a very simple but efficient web interface for hashcat password cracking tool.

## John the Ripper
*[John the Ripper](https://github.com/openwall/john) is "an Open Source password security auditing and password recovery tool available for many operating systems." The following are projects directly related to John the Ripper in one way or another.*

- [BitCracker](https://github.com/e-ago/bitcracker) - BitCracker is the first open source password cracking tool for memory units encrypted with BitLocker.
- [johnny](https://github.com/openwall/johnny) - GUI frontend to John the Ripper.

## Misc
- [920mPasswordMasks](https://github.com/jakewnuk/920mPasswordMasks) - Hashcat password masks from 920 million breach passwords filtered into groups.
- [hashgen](https://github.com/cyclone-github/hashgen) - Hashgen is a simple yet very fast CLI hash generator written in Go and cross compiled for Linux, Windows & Mac.
- [hashID](https://github.com/psypanda/hashID) - Software to identify the different types of hashes.
- [Name That Hash](https://github.com/HashPals/Name-That-Hash) - Don't know what type of hash it is? Name That Hash will name that hash type! Identify MD5, SHA256 and 300+ other hashes. Comes with a neat web app.

### Notable People
- Alotdv - [Twitter](https://twitter.com/AlongExc).
- Clem9669 - [GitHub](https://github.com/clem9669).
- Coolbry95 - [GitHub](https://github.com/coolbry95) / [Twitter](https://twitter.com/coolbry95).
- Dakykilla - [GitHub](https://github.com/dakykilla) / [Twitter](https://twitter.com/dakykilla).
- Dropdeadfu - [GitHub](https://github.com/dropdeadfu) / [Twitter](https://twitter.com/dropdeadfu).
- Epixoip - [GitHub](https://github.com/epixoip) / [Mastodon](https://infosec.exchange/@epixoip) / [Twitter](https://twitter.com/jmgosney).
- Evilmog - [GitHub](https://github.com/evilmog/) / [Mastodon](https://infosec.exchange/@evilmog) / [Twitter](https://twitter.com/Evil_Mog).
- Hydraze - [GitHub](https://github.com/Hydraze) / [Mastodon](https://infosec.exchange/@hydraze) / [Twitter](https://twitter.com/Hydraze).
- JakeWnuk - [GitHub](https://github.com/jakewnuk) / [Mastodon](https://infosec.exchange/@JakeWnuk).
- Kontrast23 - [GitHub](https://github.com/kontrast23) / [Twitter](https://twitter.com/marco_preuss).
- M3g9tr0n - [GitHub](https://github.com/m3g9tr0n) / [Twitter](https://twitter.com/m3g9tr0n).
- Matrix - [GitHub](https://github.com/matrix) / [Twitter](https://twitter.com/gm4tr1x).
- Minga - [Twitter](https://twitter.com/mingadotcom).
- N0kovo - [GitHub](https://github.com/n0kovo) / [Mastodon](https://infosec.exchange/@n0kovo) / [Twitter](https://twitter.com/n0kovos).
- NSAKEY - [GitHub](https://github.com/NSAKEY) / [Twitter](https://twitter.com/_NSAKEY) / [Website](https://abigisp.com/).
- NullMode - [GitHub](https://github.com/NullMode) / [Mastodon](https://infosec.exchange/@nullmode_@twtr.plus) / [Twitter](https://twitter.com/nullmode_).
- Paule965 - [Twitter](https://twitter.com/paule965).
- Philsmd - [GitHub](https://github.com/philsmd) / [Twitter](https://twitter.com/philsmd).
- Roycewilliams - [GitHub](https://github.com/roycewilliams) / [Mastodon](https://infosec.exchange/@tychotithonus) / [Twitter](https://twitter.com/TychoTithonus).
- RuraPenthe - [GitHub](https://github.com/bitcrackcyber) / [Mastodon](https://infosec.exchange/@rurapenthe) / [Twitter](https://twitter.com/RuraPenthe0).
- S3in!c - [GitHub](https://github.com/s3inlc) / [Mastodon](https://infosec.exchange/@s3inlc) / [Twitter](https://twitter.com/s3inlc).
- Tehnlulz - [GitHub](https://github.com/tehnlulz) / [Twitter](https://twitter.com/tehnlulz).
- The_Mechanic - [GitHub](https://github.com/th3mechanic) / [Twitter](https://twitter.com/th3_m3chan1c).
- ToXiC - [Twitter](https://twitter.com/yiannistox).
- Undeath - [GitHub](https://github.com/undeath).
- Unix-ninja - [GitHub](https://github.com/unix-ninja) / [Mastodon](https://infosec.exchange/@unix_ninja@twitterbridge.jannis.rocks) / [Twitter](https://twitter.com/unix_ninja).
- Xan - [GitHub](https://github.com/Xanadrel) / [Mastodon](https://infosec.exchange/@Xanadrel) / [Twitter](https://twitter.com/Xanadrel).

## Websites

### Communities
- [hashcat Forum](https://hashcat.net/forum/) - Forum by the developers of hashcat.
- [Hashmob](https://hashmob.net/) - A growing password recovery community aimed towards being a center point of collaboration for cryptography enthusiasts. Huge wordlist collection and a lookup service too.
- [Hashkiller Forum](https://forum.hashkiller.io/) - A password cracking forum with over 20,000 registered users.

### Lookup services
- [CMD5](https://www.cmd5.org/) - Provides online MD5 / sha1/ mysql / sha256 encryption and decryption services.
- [CrackStation](https://crackstation.net/) - Free hash lookup service supplying wordlists as well.
- [gohashmob](https://github.com/n0kovo/gohashmob) - Go CLI app to quickly lookup hashes using the HashMob API.
- [Hashes.com](https://hashes.com/) - A hash lookup service with paid features.
- [Hashkiller](https://hashkiller.io/) - A hash lookup service with a forum.
- [Online Hash Crack](https://www.onlinehashcrack.com/) - Cloud password recovery service.

## Wordlist tools
*Tools for analyzing, generating and manipulating wordlists.*

### Analysis
- [PACK](https://github.com/iphelix/pack) - A collection of utilities developed to aid in analysis of password lists in order to enhance password cracking through pattern detection of masks, rules, character-sets and other password characteristics.
- [pcfg_cracker](https://github.com/lakiw/pcfg_cracker) - This project uses machine learning to identify password creation habits of users.
- [Pipal](https://github.com/digininja/pipal) - THE password analyser.
- [PwdStat](https://github.com/jakewnuk/pwdstat) - Tool for identifying systemic password usage, creating password masks, and analyzing cracked password samples with human readable statistics to help defenders.
- [Graphcat](https://github.com/Orange-Cyberdefense/graphcat) - Generate graphs and charts based on password cracking result.

### Generation/Manipulation

- [common-substr](https://github.com/sensepost/common-substr) - Simple tool to extract the most common substrings from an input text. Built for password cracking.
- [Crunch](https://sourceforge.net/projects/crunch-wordlist/) - Crunch is a wordlist generator where you can specify a standard character set or a character set you specify. Crunch can generate all possible combinations and permutations.
- [CUPP](https://github.com/Mebus/cupp) - A tool that lets you generate wordlists by user profiling data such as birthday, nickname, address, name of a pet or relative etc.
- [duplicut](https://github.com/nil0x42/duplicut) - Remove duplicates from MASSIVE wordlist, without sorting it (for dictionary-based password cracking).
- [Gorilla](https://github.com/d4rckh/gorilla) - Tool for generating wordlists or extending an existing one using mutations.
- [Gramify](https://github.com/TheWorkingDeveloper/gramify) - Create n-grams of wordlists based on words, characters, or charsets to use in offline password attacks and data analysis.
- [Elpscrk](https://github.com/D4Vinci/elpscrk) - Elpscrk is like cupp, but it's based on permutations and statistics while being memory efficient.
- [Keyboard-Walk-Generators](https://github.com/Rich5/Keyboard-Walk-Generators) - Generate Keyboard Walk Dictionaries for cracking.
- [kwprocessor](https://github.com/hashcat/kwprocessor) - Advanced keyboard-walk generator with configureable basechars, keymap and routes.
- [maskcat](https://github.com/jakewnuk/maskcat) - Utility tool for Hashcat Masks and Password Cracking.
- [maskprocessor](https://github.com/hashcat/maskprocessor/) - High-performance word generator with a per-position configureable charset.
- [maskuni](https://github.com/flbdx/maskuni) - A standalone fast word generator in the spirit of hashcat's mask generator with unicode support.
- [Mentalist](https://github.com/sc0tfree/mentalist) - Mentalist is a graphical tool for custom wordlist generation. It utilizes common human paradigms for constructing passwords and can output the full wordlist as well as rules compatible with Hashcat and John the Ripper.
- [Phraser](https://github.com/Sparell/Phraser) - Phraser is a phrase generator using n-grams and Markov chains to generate phrases for passphrase cracking.
- [princeprocessor](https://github.com/hashcat/princeprocessor) - Standalone password candidate generator using the PRINCE algorithm.
- [Rephraser](https://github.com/travco/rephraser) - A Python-based reimagining of Phraser using Markov-chains for linguistically-correct password cracking.
- [Rling](https://github.com/Cynosureprime/rling) - RLI Next Gen (Rling), a faster multi-threaded, feature rich alternative to rli found in hashcat utilities.
- [statsprocessor](https://github.com/hashcat/statsprocessor/) - Word generator based on per-position markov-chains.
- [TTPassGen](https://github.com/tp7309/TTPassGen) - Flexible and scriptable password dictionary generator which supportss brute-force, combination, complex rule modes etc.
- [token-reverser](https://github.com/dariusztytko/token-reverser) - Words list generator to crack security tokens.
- [WikiRaider](https://github.com/NorthwaveSecurity/wikiraider) - WikiRaider enables you to generate wordlists based on country specific databases of Wikipedia.

## Wordlists
### Laguage specific
- [Albanian wordlist](https://github.com/its0x08/albanian-wordlist) - A mix of names, last names and some albanian literature.
- [Danish Phone Wordlist Generator](https://github.com/narkopolo/danish_phone_wordlist_generator) - This tool can generate wordlists of Danish phone numbers by area and/or usage (Mobile, landline etc.) Useful for password cracking or fuzzing Danish targets.
- [Danish Wordlists](https://github.com/narkopolo/danish-wordlists) - Collection of danish wordlists for cracking danish passwords.
- [French Wordlists](https://github.com/clem9669/wordlists) - This project aim to provide french word list about everything a person could use as a base password.

### Other
- [Packet Storm Wordlists](https://packetstormsecurity.com/Crackers/wordlists/page1/) - A substantial collection of different wordlists in multiple languages.
- [Rocktastic](https://labs.nettitude.com/tools/rocktastic/) - Includes many permutations of passwords and patterns that have been observed in the wild.
- [RockYou2021](https://github.com/ohmybahgosh/RockYou2021.txt) - 	RockYou2021.txt is a MASSIVE WORDLIST compiled of various other wordlists.
- [WeakPass](https://weakpass.com/) - Collection of large wordlists.

## Specific file formats
### PDF
- [pdfrip](https://github.com/mufeedvh/pdfrip) - A multi-threaded PDF password cracking utility equipped with commonly encountered password format builders and dictionary attacks.

### PEM
- [pemcracker](https://github.com/bwall/pemcracker) - Tool to crack encrypted PEM files.

### JKS
- [JKS private key cracker](https://github.com/floyd-fuh/JKS-private-key-cracker-hashcat) - Cracking passwords of private key entries in a JKS fileCracking passwords of private key entries in a JKS file.

### ZIP
- [bkcrack](https://github.com/kimci86/bkcrack) - Crack legacy zip encryption with Biham and Kocher's known plaintext attack.
- [frackzip](https://github.com/hyc/fcrackzip) - Small tool for cracking encrypted ZIP archives.

## Artificial Intelligence
- [adams](https://github.com/TheAdamProject/adams) - Reducing Bias in Modeling Real-world Password Strength via Deep Learning and Dynamic Dictionaries.
[](https://github.com/cupslab/neural_network_cracking) - Code for cracking passwords with neural networks.
- [RNN-Passwords](https://github.com/gehaxelt/RNN-Passwords) - Using the char-rnn to learn and guess passwords.
- [rulesfinder](https://github.com/synacktiv/rulesfinder) - This tool finds efficient password mangling rules (for John the Ripper or Hashcat) for a given dictionary and a list of passwords.

## Research

### Articles and Blog Posts
- [Optimizing Wordlists with Masks](https://jakewnuk.com/posts/optimizing-wordlists-w-masks/)
- [Purple Rain Attack - Password Cracking With Random Generation](https://www.netmux.com/blog/purple-rain-attack)
- [Smashing Hashes with Token Swapping Attacks](https://jakewnuk.com/posts/token-swapping-attack/)

### Papers
- [Generating Optimized Guessing Candidates toward Better Password Cracking from Multi-Dictionaries Using Relativistic GAN (2020)](https://www.mdpi.com/2076-3417/10/20/7306/htm)
- [GENPass: A General Deep Learning Model for Password Guessing with PCFG Rules and Adversarial Generation (2018)](https://ieeexplore.ieee.org/document/8422243)
- [Password Cracking Using Probabilistic Context-Free Grammars (2009)](https://www.researchgate.net/publication/220713709_Password_Cracking_Using_Probabilistic_Context-Free_Grammars)
- [Reducing Bias in Modeling Real-world Password Strength via Deep Learning and Dynamic Dictionaries (2020)](https://arxiv.org/abs/2010.12269)
- [Fast, Lean, and Accurate: Modeling Password Guessability Using Neural Networks (2016)](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/melicher)
- [PassGAN: A Deep Learning Approach for Password Guessing (2017)](https://arxiv.org/pdf/1709.00440)

### Talks
- [BsidesKY2023 - Leveling Up Password Attacks with Breach Data](https://github.com/JakeWnuk/Security-Conferences/blob/main/BsidesKY2023%20-%20Leveling%20Up%20Password%20Attacks%20with%20Breach%20Data.pdf)
- [DEF CON Safe Mode Password Village - Getting Started with Hashcat](https://www.youtube.com/watch?v=MBTJ8f6Fsmg)
- [DEF CON Safe Mode Password Village - Jeremi Gosney - Cracking at Extreme Scale](https://www.youtube.com/watch?v=4Ell1Tt23NI)
- [DEF CON 28 Safe Mode Password Village – 'Let's Crack RockYou Without Using rockyou txt'](https://www.youtube.com/watch?v=8FtXntEsZdU)
- [SecTor 2019 - Will Hunt - Hashes, Hashes Everywhere, But All I See Is Plaintext](https://sector.ca/sessions/hashes-hashes-everywhere-but-all-i-see-is-plaintext/)
- [Tailored, Machine Learning-driven Password Guessing Attacks and Mitigation at DefCamp](https://www.youtube.com/watch?v=iK6ZbD6v9Gg)
- [UNHash - Methods for better password cracking](https://media.ccc.de/v/31c3_-_5966_-_en_-_saal_1_-_201412292245_-_unhash_-_methods_for_better_password_cracking_-_tonimir_kisasondi)
- [USENIX Security '21 - Reducing Bias in Modeling Real-world Password Strength via Deep Learning and Dynamic Dictionaries](https://www.youtube.com/watch?v=Jvp3UTdCeag)
- [USENIX Security '16 - Fast, Lean, and Accurate: Modeling Password Guessability Using Neural Networks
](https://www.youtube.com/watch?v=GgaZ_LxsL_8)


text:
name: CI
on:
  pull_request:
    branches: [main]
jobs:
  Awesome_Lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - run: npx awesome-lint


text:
---
layout: default
---

404

Page not found :(

The requested page could not be found.

repo_name: yearn/YIPS

repo_language: HTML

file_name: config


text: yips.yearn.finance


text:
# Welcome to Jekyll!
#
# This config file is meant for settings that affect your whole blog, values
# which you are expected to set up once and rarely edit after that. If you find
# yourself editing this file very often, consider using Jekyll's data files
# feature for the data you need to update frequently.
#
# For technical reasons, this file is *NOT* reloaded automatically when you use
# 'bundle exec jekyll serve'. If you change this file, please restart the server process.

# Site settings
# These are used to personalize your new site. If you look in the HTML files,
# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
# You can create any custom variable you would like, and they will be accessible
# in the templates via {{ site.myvariable }}.
description: >-
  Yearn Improvement Proposals (YIPs) describe standards for the Yearn
  platform, including core protocol specifications, client APIs, and contract
  standards.
url: "https://yips.yearn.finance"
repository: yearn/YIPS
twitter_username: iearnfinance
github_username: yearn
header_pages:
  - all-yip.html
twitter:
  card: summary
  username: iearnfinance

# Build settings
markdown: kramdown
theme: minima
plugins:
  - jekyll-seo-tag

permalink: /:slug

defaults:
  - scope:
      path: "YIPS"
    values:
      layout: "yip"
  - scope:
      path: ""
    values:
      image: "/assets/og_image.png"

exclude:
  - Gemfile
  - Gemfile.lock
  - node_modules
  - vendor/bundle/
  - vendor/cache/
  - vendor/gems/
  - vendor/ruby/
  - yip-X.md


text:
---
layout: default
title: Yearn Improvement Proposals
---

  Yearn Improvement Proposals

  Yearn Improvement Proposals (YIPs) describe standards for the Yearn platform,
  including core protocol specifications, client APIs, and contract standards.

Contributing

Review YIP-0.

Fork the repository by clicking "Fork" in the top right.

    Add your YIP to your fork of the repository. There is a
    template YIP here.

    Submit a Pull Request to Yearn's
    YIPs repository.

  Your first PR should be a first draft of the final YIP. It must meet the
  formatting criteria enforced by the build (largely, correct metadata in the
  header). An editor will manually review the first PR for a new YIP and assign
  it a number before merging it. Make sure you include a
  discussions-to header with the URL to a discussion forum or open
  GitHub issue where people can discuss the YIP as a whole.

  If your YIP requires images, the image files should be included in a
  subdirectory of the `assets` folder for that YIP as follow:
  assets/yip-X (for yip X). When linking to an image in the
  YIP, use relative links such as ../assets/yip-X/image.png.

  When you believe your YIP is mature and ready to progress past the WIP phase,
  you should ask to have your issue added to the next governance call where it
  can be discussed for inclusion in a future platform upgrade. If the community
  agrees to include it, the YIP editors will update the state of your YIP to
  Approved.

YIP Status Terms

WIP - a YIP that is still being developed.

    Proposed - a YIP that is ready to be reviewed in a
    governance call.

    Approved - a YIP that has been accepted for implementation
    by the Yearn Community.

    Implemented - a YIP that has been released to mainnet.

Rejected - a YIP that has been rejected.

    Withdrawn - a YIP that has been withdrawn by the author(s).

    Deferred - a YIP that is pending another YIP/some other
    change that should be bundled with it together.

    Moribund - a YIP that was implemented but is now obsolete
    and requires no explicit replacement.