Full Code of bee-san/Ciphey for AI

master 5dfbe9330070 cached
144 files
581.8 KB
166.0k tokens
632 symbols
1 requests
Download .txt
Showing preview only (620K chars total). Download the full file or copy to clipboard to get everything.
Repository: bee-san/Ciphey
Branch: master
Commit: 5dfbe9330070
Files: 144
Total size: 581.8 KB

Directory structure:
gitextract_ft4u3o1q/

├── .all-contributorsrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   ├── feature_request.md
│   │   └── maintenance_suggestion.md
│   ├── config.yml
│   ├── dependabot.yml
│   ├── lock.yml
│   ├── release-drafter.yml
│   └── workflows/
│       ├── coverage.yml
│       ├── release.yml
│       ├── releasetestpypi.yml
│       ├── terminaltest.yml
│       └── tests2.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Pictures_for_README/
│   └── .gitattributes
├── README.md
├── ciphey/
│   ├── __init__.py
│   ├── __main__.py
│   ├── basemods/
│   │   ├── Checkers/
│   │   │   ├── __init__.py
│   │   │   ├── any.py
│   │   │   ├── brandon.py
│   │   │   ├── entropy.py
│   │   │   ├── ezcheck.py
│   │   │   ├── format.py
│   │   │   ├── gtest.py
│   │   │   ├── human.py
│   │   │   ├── quadgrams.py
│   │   │   ├── quorum.py
│   │   │   ├── regex.py
│   │   │   └── what.py
│   │   ├── Crackers/
│   │   │   ├── __init__.py
│   │   │   ├── affine.py
│   │   │   ├── ascii_shift.py
│   │   │   ├── baconian.py
│   │   │   ├── caesar.py
│   │   │   ├── hash.py
│   │   │   ├── rot47.py
│   │   │   ├── soundex.py
│   │   │   ├── vigenere.py
│   │   │   ├── xandy.py
│   │   │   └── xortool.py
│   │   ├── Decoders/
│   │   │   ├── __init__.py
│   │   │   ├── a1z26.py
│   │   │   ├── atbash.py
│   │   │   ├── base58_bitcoin.py
│   │   │   ├── base58_flickr.py
│   │   │   ├── base58_ripple.py
│   │   │   ├── base62.py
│   │   │   ├── base64_url.py
│   │   │   ├── base65536.py
│   │   │   ├── base69.py
│   │   │   ├── base91.py
│   │   │   ├── bases.py
│   │   │   ├── baudot.py
│   │   │   ├── binary.py
│   │   │   ├── braille.py
│   │   │   ├── brainfuck.py
│   │   │   ├── decimal.py
│   │   │   ├── dna.py
│   │   │   ├── dtmf.py
│   │   │   ├── galactic.py
│   │   │   ├── gzip.py
│   │   │   ├── hexadecimal.py
│   │   │   ├── leetspeak.py
│   │   │   ├── letters.archive
│   │   │   ├── morse_code.py
│   │   │   ├── multi_tap.py
│   │   │   ├── octal.py
│   │   │   ├── reverse.py
│   │   │   ├── tap_code.py
│   │   │   ├── unicode.py
│   │   │   ├── url.py
│   │   │   ├── uuencode.py
│   │   │   └── z85.py
│   │   ├── Resources/
│   │   │   ├── __init__.py
│   │   │   ├── cipheydists.py
│   │   │   └── files.py
│   │   ├── Searchers/
│   │   │   ├── __init__.py
│   │   │   ├── astar.py
│   │   │   ├── atar.md
│   │   │   ├── ausearch.py
│   │   │   ├── imperfection.py
│   │   │   └── perfection.py
│   │   └── __init__.py
│   ├── ciphey.py
│   ├── common.py
│   ├── iface/
│   │   ├── __init__.py
│   │   ├── _config.py
│   │   ├── _fwd.py
│   │   ├── _modules.py
│   │   └── _registry.py
│   └── mathsHelper.py
├── codecov.yml
├── license
├── noxfile.py
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── brandon_interface.md
│   ├── cli.py
│   ├── dict.py
│   ├── enciphey.py
│   ├── generate_tests.py
│   ├── integration.py
│   ├── lukas.py
│   ├── speed_test.archive
│   ├── test_advanced_ciphers.py
│   ├── test_click.py
│   ├── test_click_printing.py
│   ├── test_main.py
│   ├── test_quick.py
│   └── test_regex.py
├── tools/
│   └── freq_analysis.py
└── translations/
    ├── de/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── fr/
    │   └── README.md
    ├── hu/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── id/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── it/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── nl/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── pt-br/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── ru/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── th/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    └── zh/
        ├── CODE_OF_CONDUCT.md
        ├── CONTRIBUTING.md
        └── README.md

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

================================================
FILE: .all-contributorsrc
================================================
{
  "files": [
    "README.md"
  ],
  "imageSize": 100,
  "commit": false,
  "contributors": [
    {
      "login": "cyclic3",
      "name": "cyclic3",
      "avatar_url": "https://avatars1.githubusercontent.com/u/15613874?v=4",
      "profile": "https://github.com/Cyclic3",
      "contributions": [
        "design",
        "maintenance",
        "code",
        "ideas"
      ]
    },
    {
      "login": "brandonskerritt",
      "name": "Brandon",
      "avatar_url": "https://avatars3.githubusercontent.com/u/10378052?v=4",
      "profile": "https://skerritt.blog",
      "contributions": [
        "design",
        "maintenance",
        "code",
        "ideas"
      ]
    },
    {
      "login": "michalani",
      "name": "michalani",
      "avatar_url": "https://avatars0.githubusercontent.com/u/27767884?v=4",
      "profile": "https://github.com/michalani",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "ashb07",
      "name": "ashb07",
      "avatar_url": "https://avatars2.githubusercontent.com/u/24845568?v=4",
      "profile": "https://github.com/ashb07",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "TheAlcanian",
      "name": "Shardion",
      "avatar_url": "https://avatars3.githubusercontent.com/u/22127191?v=4",
      "profile": "https://github.com/TheAlcanian",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "Bryzizzle",
      "name": "Bryan",
      "avatar_url": "https://avatars0.githubusercontent.com/u/57810197?v=4",
      "profile": "https://github.com/Bryzizzle",
      "contributions": [
        "translation",
        "doc"
      ]
    },
    {
      "login": "lukasgabriel",
      "name": "Lukas Gabriel",
      "avatar_url": "https://avatars0.githubusercontent.com/u/52338810?v=4",
      "profile": "https://lukasgabriel.net",
      "contributions": [
        "code",
        "bug",
        "translation",
        "ideas"
      ]
    },
    {
      "login": "DarshanBhoi",
      "name": "Darshan",
      "avatar_url": "https://avatars2.githubusercontent.com/u/70128281?v=4",
      "profile": "https://github.com/DarshanBhoi",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "SkeletalDemise",
      "name": "SkeletalDemise",
      "avatar_url": "https://avatars1.githubusercontent.com/u/29117662?v=4",
      "profile": "https://github.com/SkeletalDemise",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "cclauss",
      "name": "Christian Clauss",
      "avatar_url": "https://avatars3.githubusercontent.com/u/3709715?v=4",
      "profile": "https://www.patreon.com/cclauss",
      "contributions": [
        "code",
        "bug"
      ]
    },
    {
      "login": "machinexa2",
      "name": "Machinexa2",
      "avatar_url": "https://avatars1.githubusercontent.com/u/60662297?v=4",
      "profile": "http://machinexa.xss.ht",
      "contributions": [
        "content"
      ]
    },
    {
      "login": "anantverma275",
      "name": "Anant Verma",
      "avatar_url": "https://avatars1.githubusercontent.com/u/18184503?v=4",
      "profile": "https://github.com/anantverma275",
      "contributions": [
        "code",
        "bug"
      ]
    },
    {
      "login": "XVXTOR",
      "name": "XVXTOR",
      "avatar_url": "https://avatars1.githubusercontent.com/u/40268197?v=4",
      "profile": "https://github.com/XVXTOR",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Itamikame",
      "name": "Itamikame",
      "avatar_url": "https://avatars2.githubusercontent.com/u/59034423?v=4",
      "profile": "https://github.com/Itamikame",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "MikeMerz",
      "name": "MikeMerz",
      "avatar_url": "https://avatars3.githubusercontent.com/u/50526795?v=4",
      "profile": "https://github.com/MikeMerz",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "jacobggman",
      "name": "Jacob Galam",
      "avatar_url": "https://avatars2.githubusercontent.com/u/30216976?v=4",
      "profile": "https://github.com/jacobggman",
      "contributions": [
        "code",
        "bug"
      ]
    },
    {
      "login": "TuxTheXplorer",
      "name": "TuxTheXplorer",
      "avatar_url": "https://avatars1.githubusercontent.com/u/37508897?v=4",
      "profile": "https://tuxthexplorer.github.io/",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "Itamai",
      "name": "Itamai",
      "avatar_url": "https://avatars3.githubusercontent.com/u/53093696?v=4",
      "profile": "https://github.com/Itamai",
      "contributions": [
        "code",
        "bug"
      ]
    },
    {
      "login": "Termack",
      "name": "Filipe",
      "avatar_url": "https://avatars2.githubusercontent.com/u/26333901?v=4",
      "profile": "https://github.com/Termack",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "malathit",
      "name": "Malathi",
      "avatar_url": "https://avatars0.githubusercontent.com/u/2684148?v=4",
      "profile": "https://github.com/malathit",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "HexChaos",
      "name": "Jack",
      "avatar_url": "https://avatars1.githubusercontent.com/u/8947820?v=4",
      "profile": "https://hexchaos.xyz/",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "yafkari",
      "name": "Younes",
      "avatar_url": "https://avatars3.githubusercontent.com/u/41365655?v=4",
      "profile": "https://github.com/yafkari",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "Marnick39",
      "name": "Marnick Vandecauter",
      "avatar_url": "https://avatars2.githubusercontent.com/u/17315511?v=4",
      "profile": "https://gitlab.com/Marnick39",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "mav8557",
      "name": "Michael V",
      "avatar_url": "https://avatars0.githubusercontent.com/u/47306745?v=4",
      "profile": "https://github.com/mav8557",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "chuinzer",
      "name": "chuinzer",
      "avatar_url": "https://avatars2.githubusercontent.com/u/64257785?v=4",
      "profile": "https://github.com/chuinzer",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "blackcat-917",
      "name": "blackcat-917",
      "avatar_url": "https://avatars1.githubusercontent.com/u/53786619?v=4",
      "profile": "https://github.com/blackcat-917",
      "contributions": [
        "translation",
        "doc"
      ]
    },
    {
      "login": "Ozzyz",
      "name": "Åsmund Brekke",
      "avatar_url": "https://avatars3.githubusercontent.com/u/6113447?v=4",
      "profile": "https://github.com/Ozzyz",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "sashreek1",
      "name": "Sashreek Shankar",
      "avatar_url": "https://avatars1.githubusercontent.com/u/45600974?v=4",
      "profile": "https://github.com/sashreek1",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "cryptobadger",
      "name": "cryptobadger",
      "avatar_url": "https://avatars2.githubusercontent.com/u/26308101?v=4",
      "profile": "https://github.com/cryptobadger",
      "contributions": [
        "code",
        "bug"
      ]
    },
    {
      "login": "e1fy",
      "name": "elf",
      "avatar_url": "https://avatars3.githubusercontent.com/u/61194758?v=4",
      "profile": "https://github.com/e1fy",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "rogercyyu",
      "name": "Roger Yu",
      "avatar_url": "https://avatars0.githubusercontent.com/u/45835736?v=4",
      "profile": "https://github.com/rogercyyu",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "JesseEmond",
      "name": "dysleixa",
      "avatar_url": "https://avatars.githubusercontent.com/u/1843555?v=4",
      "profile": "https://github.com/JesseEmond",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "mohzulfikar",
      "name": "Mohammad Zulfikar",
      "avatar_url": "https://avatars.githubusercontent.com/u/48849323?v=4",
      "profile": "http://mohzulfikar.me",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "AABur",
      "name": "Alexander Burchenko",
      "avatar_url": "https://avatars.githubusercontent.com/u/41373199?v=4",
      "profile": "https://github.com/AABur",
      "contributions": [
        "translation"
      ]
    },
    {
      "login": "PunGrumpy",
      "name": "Noppakorn Kaewsalabnil",
      "avatar_url": "https://avatars.githubusercontent.com/u/108584943?v=4?s=100",
      "profile": "https://github.com/PunGrumpy",
      "contributions": [
        "translation"
      ]
    }
  ],
  "contributorsPerLine": 7,
  "projectName": "Ciphey",
  "projectOwner": "Ciphey",
  "repoType": "github",
  "repoHost": "https://github.com",
  "skipCi": true
}


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: bee-san
custom: ["https://www.buymeacoffee.com/beecodes", "https://paypal.me/cipheydevs"]


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug

---

**⚠️IMPORTANT⚠️ if you do not fill this out, we will automatically delete your issue. We will not help anyone that cannot fill out this template.**

- [ ] Have you read our [Wiki page "Common Issues & Their Solutions"?](https://github.com/Ciphey/Ciphey/wiki/Common-Issues-&-Their-Solutions)

**Describe the bug**
A clear and concise description of what the bug is.

**Plaintext**
**⚠️IMPORTANT⚠️ The below code is non-negotiable for "Ciphey didn't decrypt...." problems. If you do not tell us your plaintext, we will not help you.** 

```
Include your plaintext here, replacing this 
```
**Version**
**⚠️IMPORTANT⚠️ We need this information because different environments will induce different bugs in Ciphey**
 - OS/Distro: [e.g. Windows, Debian 11.0, Arch, OS X El Capitan]
 - Python version: [python3 --version]
 - Ciphey versions: [python3 -m pip show ciphey cipheycore cipheydists]
 - Did you use Docker?

**Verbose Output**
**⚠️IMPORTANT⚠️ Verbose output will tell us why it's not working the way we expected it to be.**
Run Ciphey with `ciphey -vvv` and paste the results into [Pastebin.com](https://pastebin.com) or a [GitHub Gist](https://gist.github.com/)

**To Reproduce**
Steps to reproduce the behavior:
1. What input did you use?
2. What flags / arguments did you use?

**Expected behavior**
A clear and concise description of what you expected to happen.

**Any other information?**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: brandonskerritt

---
### Problem:
_What exactly do you think is missing? How does it impact you? Are there any hacks that people use instead?_

### Solution:
_How could this problem be solved? What could be added? How could it be integrated into the current system?_


================================================
FILE: .github/ISSUE_TEMPLATE/maintenance_suggestion.md
================================================
---
name: Maintenance suggestion
about: Suggest refactoring/restructuring that would help
title: ''
labels: maintenance
assignees: brandonskerritt

---
### Idea
_What exactly do you want to do?_

### Pros
_How would it help the code? Does it make things faster, or the code more maintainable?_

### Cons
_Would this break anything? Would it mean a rewrite of all the code?_


================================================
FILE: .github/config.yml
================================================
todo:
  keyword: "@TODO"


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: pip
  directory: "/"
  schedule:
    interval: daily
  open-pull-requests-limit: 10
  ignore:
  - dependency-name: black
    versions:
    - 21.4b0
    - 21.4b1


================================================
FILE: .github/lock.yml
================================================
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app

# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 60

# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false

# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []

# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false

# Comment to post before locking. Set to `false` to disable
lockComment: >
  This thread has been automatically locked since there has not been
  any recent activity after it was closed. Please open a new issue for
  related bugs.

# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true

# Limit to only `issues` or `pulls`
# only: issues

# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
#   exemptLabels:
#     - help-wanted
#   lockLabel: outdated

# pulls:
#   daysUntilLock: 30

# Repository to extend settings from
# _extends: repo


================================================
FILE: .github/release-drafter.yml
================================================
template: |
  ## What’s Changed

  $CHANGES


================================================
FILE: .github/workflows/coverage.yml
================================================
name: coverage
on: [push, pull_request]
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: [3.6, 3.7, pypy3]
        # exclude:
        #   - os: macos-latest
        #     python-version: 3.8
        #   - os: windows-latest
        #     python-version: 3.6
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
      - name: Tests with Nox

  coverage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v2
      with:
        python-version: '3.8'
        architecture: x64
    - run: pip3 install nox==2019.11.9
    - run: pip3 install poetry==1.0.5
    - run: nox --sessions tests coverage
      env:
        CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}




================================================
FILE: .github/workflows/release.yml
================================================
# .github/workflows/release.yml
name: Release
on:
  release:
    types: [published]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v1
      with:
        python-version: '3.8'
        architecture: x64
    - run: pip install nox
    - run: pip install poetry
    - run: nox
    - run: poetry build
    - run: poetry publish --username=__token__ --password=${{ secrets.PYPI_TOKEN }}


================================================
FILE: .github/workflows/releasetestpypi.yml
================================================
# .github/workflows/test-pypi.yml
name: TestPyPI
on:
  push:
    branches:
      - master
jobs:
  test_pypi:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v1
      with:
        python-version: '3.8'
        architecture: x64
    - run: pip install poetry
    - run: >-
        poetry version patch &&
        version=$(poetry version | awk '{print $2}') &&
        poetry version $version.dev.$(date +%s)
    - run: poetry build
    - uses: pypa/gh-action-pypi-publish@v1.0.0a0
      with:
        user: __token__
        password: ${{ secrets.TEST_PYPI_TOKEN }}
        repository_url: https://test.pypi.org/legacy/


================================================
FILE: .github/workflows/terminaltest.yml
================================================
on: pull_request
name: Ciphey terminal test
jobs:
  terminal_test:
    name: On ubuntu-latest with python
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.7, 3.8, 3.9]
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Build ciphey
      run: |
        python -m pip install poetry
        poetry install
    - name: Test ciphey with plain text
      run: |
        plain_text="hello. Testing Ciphey."
        ciphey_out=$(poetry run ciphey -q -t "$plain_text")
        if [ "$ciphey_out" == "$plain_text" ]
        then
          exit 0
        else
          echo "Ciphey decryption on plain text failed"
          exit 1
        fi
    - name: Test ciphey with base64 encoded text
      run: |
        plain_text="hello. Testing Ciphey."
        base64_encoded=$(echo -n "$plain_text" | base64)
        ciphey_out=$(poetry run ciphey -q -t "$base64_encoded")
        if [ "$ciphey_out" == "$plain_text" ]
        then
          exit 0
        else
          echo "Ciphey decryption on base64 encoded string failed"
          exit 1
        fi 


================================================
FILE: .github/workflows/tests2.yml
================================================
name: Tests
on: [push, pull_request]
jobs:
  tests:
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.7', '3.8', '3.9']
        os: [ubuntu-latest, windows-latest] #macos-latest,
    runs-on: ${{ matrix.os }}
    name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
        architecture: x64
    - run: python -m pip install --upgrade pip
    - run: pip install codespell flake8 nox poetry
    - run: codespell --ignore-words-list="nd,te" --skip="translations,*.archive"
    - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
    - run: python -m nox


================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/git,python,virtualenv
# Edit at https://www.gitignore.io/?templates=git,python,virtualenv

### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig


# Created by https://www.gitignore.io/api/venv
# Edit at https://www.gitignore.io/?templates=venv

### venv ###
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
.Python
pyvenv.cfg
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
pip-selfcheck.json
ciphey.egg-info
dist/
dist

hansard.txt
poetry.lock
# End of https://www.gitignore.io/api/venv

# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest


# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

### VirtualEnv ###
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
pip-selfcheck.json

# End of https://www.gitignore.io/api/git,python,virtualenv
.vscode/

.vim/coc-settings.json

# Poetry stuff
dist/
poetry.lock

# Nano
*.swp

# PyCharm
.idea/

ciphey/LanguageChecker/create\?max_size=60&spelling=US&spelling=GBs&max_variant=2&diacritic=both&special=hacker&special=roman-numerals&download=wordlist&encoding=utf-8&format=inline

ciphey/LanguageChecker/create\?max_size=80&spelling=US&spelling=GBs&spelling=GBz&spelling=CA&spelling=AU&max_variant=2&diacritic=both&special=hacker&special=roman-numerals&download=wordlist&encoding=utf-8&format=inline

ciphey/LanguageChecker/aspell.txt
dictionary.txt
aspell.txt

ciphey.spec

ciphey/__main__.spec

__main__.spec

.entry_point.spec/entry_point.spec

BEANOS INVADES THE FORTNITE ITEM SHOP AT 8_00 PM.EXE-uG0WJcr-cuI.f299.mp4.part

run.yml

tests/interface.rst


# Test Generator
test_main_generated.py

run.yml

tests/interface.rst

test.py

# Mac OS Files
.DS_Store
.AppleDouble
.LSOverride
Icon
._*


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
 advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
 address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
 professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at brandon_skerrit. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
<https://www.contributor-covenant.org/faq>


================================================
FILE: CONTRIBUTING.md
================================================
<p align="center">
Translations <br>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>🇩🇪 DE   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/hu/CONTRIBUTING.md>🇭🇺 HU   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/id/CONTRIBUTING.md>🇮🇩 ID   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/it/CONTRIBUTING.md>🇮🇹 IT   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/nl/CONTRIBUTING.md>🇳🇱 NL   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/pt-br/CONTRIBUTING.md>🇧🇷 PT-BR   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/ru/CONTRIBUTING.md>🇷🇺 RU   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/zh/CONTRIBUTING.md>🇨🇳 ZH   </a>
</p>

Howdy!

So, you're interested in contributing to Ciphey? 🤔

Perhaps you're confused as to where to start, or you believe your coding skills aren't "good enough"? Well, for the latter - that's ridiculous! We're perfectly okay with "bad code" and even then if you're reading this document you're probably a great programmer. I mean, newbies don't often learn to contribute to GitHub projects 😉

Here are some ways you can contribute to Ciphey:

- Add a new language 🧏
- Add more encryption methods 📚
- Create more documentation (very important! We would be eternally grateful)
- Fix bugs submitted via GitHub issues (we can support you in this 😊)
- Refactor the code base 🥺

If these sound hard, do not worry! This document will walk you through exactly how to achieve any of these. Also, your name will be added to Ciphey's contributors list, and we'll be eternally grateful! 🙏

We have a small Discord chat for you to talk to the developers and get some help. Alternatively, you can write a GitHub issue for your suggestion. If you want to be added to the Discord, DM us or ask us somehow.

[Discord Server](https://discord.gg/KfyRUWw)

# How to contribute

Ciphey is always in need of more decryption tools! To learn how to integrate code into ciphey, check out:

- <https://github.com/Ciphey/Ciphey/wiki/Adding-your-own-ciphers> for a simple tutorial
- <https://github.com/Ciphey/Ciphey/wiki/Extending-Ciphey> for a API reference

It would be nice if you wrote some tests for it, by simply copying a function in the Ciphey/tests/test_main.py and replacing the ciphertext with something encoded with your cipher. If you don't add tests, we will probably still merge it, but it will be much harder for us to diagnose bugs!

It goes without saying that we will add you to the list of contributors for your hard work!

# Add a new language 🧏

The default language checker, `brandon`, works with multiple languages. Now, this may sound daunting.
But honestly, all you've got to do is take a dictionary, do a little analysis (we've written code to help you with this), add the dictionaries and analysis to a repo. And then add the option to `settings.yml`.

# Create more documentation

Documentation is the most important part of Ciphey. No documentation is extreme code debt, and we don't want that.

Trust me when I say if you contribute to great documentation you will be seen on the same level as code contributors. Documentation is absolutely vital.

There are lots of ways you can add documentation.

- Doc strings in the code
- Improving our current documentation (README, this file, our Ciphey Wiki pages)
- Translating documentation

And much more!

# Fix bugs

Visit our GitHub issues page to find all the bugs that Ciphey has! Squash them, and you'll be added to the contributors list. ;)

# Refactor the code base

Not all of Ciphey follows PEP8, and some of the code is repeated.


================================================
FILE: Pictures_for_README/.gitattributes
================================================
render1596301769504.gif filter=lfs diff=lfs merge=lfs -text


================================================
FILE: README.md
================================================
<p align="center">
Translations <br>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/fr/README.md>🇫🇷 FR   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/hu/README.md>🇭🇺 HU   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/id/README.md>🇮🇩 ID   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/it/README.md>🇮🇹 IT   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/nl/README.md>🇳🇱 NL   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/pt-br/README.md>🇧🇷 PT-BR   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/ru/README.md>🇷🇺 RU   </a>
<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/zh/README.md>🇨🇳 ZH   </a>
<a href="https://github.com/Ciphey/Ciphey/tree/master/translations/th/README.md">🇹🇭 TH   </a>
 <br><br>
➡️
<a href="https://github.com/Ciphey/Ciphey/wiki">Documentation</a> |
<a href="https://discord.gg/zYTM3rZM4T">Discord</a> |
 <a href="https://github.com/Ciphey/Ciphey/wiki/Installation">Installation Guide</a>
 ⬅️

<br>
  <img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/binoculars.png" alt="Ciphey">
</p>

<p align="center">
<img src="https://pepy.tech/badge/ciphey">
 <img src="https://pepy.tech/badge/ciphey/month">
  <a href="https://discord.gg/zYTM3rZM4T"><img alt="Discord" src="https://img.shields.io/discord/754001738184392704"></a>
<a href="https://pypi.org/project/ciphey/"><img src="https://img.shields.io/pypi/v/ciphey.svg"></a>
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="Ciphey">

<br>
Fully automated decryption/decoding/cracking tool using natural language processing & artificial intelligence, along with some common sense.
</p>
<hr>

## [Installation Guide](https://github.com/Ciphey/Ciphey/wiki/Installation)

| <p align="center"><a href="https://pypi.org/project/ciphey">🐍 Python | <p align="center"><a href="https://hub.docker.com/r/remnux/ciphey">🐋 Docker (Universal) | <p align="center"><a href="https://ports.macports.org/port/ciphey/summary">🍎 MacPorts (macOS) | <p align="center"><a href="https://formulae.brew.sh/formula/ciphey">🍺 Homebrew (macOS/Linux) |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |--------------------------------------------------------------------------------- |
| <p align="center"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/python.png" /></p>    | <p align="center"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/docker.png" /></p> | <p align="center"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/macports.png" /></p> | <p align="center"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/homebrew.png" /></p> |
| `python3 -m pip install ciphey --upgrade` | `docker run -it --rm remnux/ciphey` | `sudo port install ciphey` | `brew install ciphey` |

| Linux                                                                                                                   | Mac OS                                                                                                                     | Windows                                                                                                                   |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ciphey/ciphey/Python%20application?label=Linux) | ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ciphey/ciphey/Python%20application?label=Mac%20OS) | ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ciphey/ciphey/Python%20application?label=Windows) |

<hr>

# 🤔 What is this?

Input encrypted text, get the decrypted text back.

> "What type of encryption?"

That's the point. You don't know, you just know it's possibly encrypted. Ciphey will figure it out for you.

Ciphey can solve most things in 3 seconds or less.

<p align="center" href="https://asciinema.org/a/336257">
  <img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/index.gif" alt="Ciphey demo">
</p>

Ciphey aims to be a tool to automate a lot of decryptions & decodings such as multiple base encodings, classical ciphers, hashes or more advanced cryptography.

If you don't know much about cryptography, or you want to quickly check the ciphertext before working on it yourself, Ciphey is for you.

**The technical part.** Ciphey uses a custom built artificial intelligence module (_AuSearch_) with a _Cipher Detection Interface_ to approximate what something is encrypted with. And then a custom-built, customisable natural language processing _Language Checker Interface_, which can detect when the given text becomes plaintext.

No neural networks or bloated AI here. We only use what is fast and minimal.

And that's just the tip of the iceberg. For the full technical explanation, check out our [documentation](https://github.com/Ciphey/Ciphey/wiki).

# ✨ Features

- **50+ encryptions/encodings supported** such as binary, Morse code and Base64. Classical ciphers like the Caesar cipher, Affine cipher and the Vigenere cipher. Along with modern encryption like repeating-key XOR and more. **[For the full list, click here](https://github.com/Ciphey/Ciphey/wiki/Supported-Ciphers)**
- **Custom Built Artificial Intelligence with Augmented Search (AuSearch) for answering the question "what encryption was used?"** Resulting in decryptions taking less than 3 seconds.
- **Custom built natural language processing module** Ciphey can determine whether something is plaintext or not. Whether that plaintext is JSON, a CTF flag, or English, Ciphey can get it in a couple of milliseconds.
- **Multi Language Support** at present, only German & English (with AU, UK, CAN, USA variants).
- **Supports encryptions and hashes** Which the alternatives such as CyberChef Magic do not.
- **[C++ core](https://github.com/Ciphey/CipheyCore)** Blazingly fast.

# 🔭 Ciphey vs CyberChef

## 🔁 Base64 Encoded 42 times

<table>
  <tr>
  <th>Name</th>
    <th>⚡ Ciphey ⚡ </th>
    <th>🐢 CyberChef 🐢</th>
  </tr>
  <tr>
  <th>Gif</th>
    <td><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/ciphey_gooder_cyberchef.gif" alt="The guy she tells you not to worry about"></td>
    <td><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/not_dying.gif" alt="You"></td>
  </tr>
  <tr>
  <th>Time</th>
    <td>2 seconds</td>
    <td>6 seconds</td>
  </tr>
    <tr>
  <th>Setup</th>
    <td><ul><li>Run ciphey on the file</li></ul></td>
    <td><ul><li>Set the regex param to "{"</li><li>You need to know how many times to recurse</li><li>You need to know it's Base64 all the way down</li><li>You need to load CyberChef (it's a bloated JS app)</li><li>Know enough about CyberChef to create this pipeline</li><li>Invert the match</li></ul></td>
  </tr>
</table>

<sub><b>Note</b> The gifs may load at different times, so one may appear significantly faster than another.</sub><br>
<sub><b>A note on magic </b>CyberChef's most similar feature to Ciphey is Magic. Magic fails instantly on this input and crashes. The only way we could force CyberChef to compete was to manually define it.</sub>

We also tested CyberChef and Ciphey with a **6gb file**. Ciphey cracked it in **5 minutes and 54 seconds**. CyberChef crashed before it even started.

## 📊 Ciphey vs Katana vs CyberChef Magic

| **Name**                                   | ⚡ Ciphey ⚡ | 🗡️ Katana 🗡️ | 🐢 CyberChef Magic 🐢 |
| ------------------------------------------ | ------------ | ------------ | --------------------- |
| Advanced Language Checker                  | ✅           | ❌           | ✅                    |
| Supports Encryptions                       | ✅           | ✅           | ❌                    |
| Releases named after Dystopian themes 🌃   | ✅           | ❌           | ❌                    |
| Supports hashes                            | ✅           | ✅           | ❌                    |
| Easy to set up                             | ✅           | ❌           | ✅                    |
| Can guess what something is encrypted with | ✅           | ❌           | ❌                    |
| Created for hackers by hackers             | ✅           | ✅           | ❌                    |

# 🎬 Getting Started

If you're having trouble with installing Ciphey, [read this.](https://github.com/Ciphey/Ciphey/wiki/Common-Issues-&-Their-Solutions)

## ‼️ Important Links (Docs, Installation guide, Discord Support)

| Installation Guide                                                          | Documentation                                             | Discord                                     | Docker Image (from REMnux)                                                                          |
| --------------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| 📖 [Installation Guide](https://github.com/Ciphey/Ciphey/wiki/Installation) | 📚 [Documentation](https://github.com/Ciphey/Ciphey/wiki) | 🦜 [Discord](https://discord.gg/zYTM3rZM4T) | 🐋 [Docker Documentation](https://docs.remnux.org/run-tools-in-containers/remnux-containers#ciphey) |

## 🏃‍♀️Running Ciphey

There are 3 ways to run Ciphey.

1. File Input `ciphey -f encrypted.txt`
2. Unqualified input `ciphey -- "Encrypted input"`
3. Normal way `ciphey -t "Encrypted input"`

![Gif showing 3 ways to run Ciphey](https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/3ways.gif)

To get rid of the progress bars, probability table, and all the noise use the quiet mode.

`ciphey -t "encrypted text here" -q`

For a full list of arguments, run `ciphey --help`.

### ⚗️ Importing Ciphey

You can import Ciphey\'s main and use it in your own programs and code. `from Ciphey.__main__ import main`

# 🎪 Contributors

Ciphey was invented by [Bee](https://github.com/bee-san) in 2008, and revived in 2019. Ciphey wouldn't be where it was today without [Cyclic3](https://github.com/Cyclic3) - president of UoL's Cyber Security Society.

Ciphey was revived & recreated by the [Cyber Security Society](https://www.cybersoc.cf/) for use in CTFs. If you're ever in Liverpool, consider giving a talk or sponsoring our events. Email us at `cybersecurity@society.liverpoolguild.org` to find out more 🤠

**Major Credit** to George H for working out how we could use proper algorithms to speed up the search process.
**Special thanks** to [varghalladesign](https://www.facebook.com/varghalladesign) for designing the logo. Check out their other design work!

## 🐕‍🦺 [Contributing](https://github.com/Ciphey/Ciphey/wiki/Contributing)

Don't be afraid to contribute! We have many, many things you can do to help out. Each of them labelled and easily explained with examples. If you're trying to contribute but stuck, tag @bee-san ✨

Alternatively, join the Discord group and send a message there (link in [contrib file](https://github.com/Ciphey/Ciphey/wiki/Contributing)) or at the top of this README as a badge.

Please read the [contributing file](https://github.com/Ciphey/Ciphey/wiki/Contributing) for exact details on how to contribute ✨

By doing so, you'll get your name added to the README below and get to be apart of an ever-growing project!
[![Stargazers over time](https://starchart.cc/Ciphey/Ciphey.svg)](https://starchart.cc/Ciphey/Ciphey)

## 💰 Financial Contributors

The contributions will be used to fund not only the future of Ciphey and its authors, but also Cyber Security Society at the University of Liverpool.

GitHub doesn't support "sponsor this project and we'll evenly distribute the money", so pick a link and we'll sort it out on our end 🥰

## ✨ Contributors

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/Cyclic3"><img src="https://avatars1.githubusercontent.com/u/15613874?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cyclic3</b></sub></a><br /><a href="#design-cyclic3" title="Design">🎨</a> <a href="#maintenance-cyclic3" title="Maintenance">🚧</a> <a href="https://github.com/Ciphey/Ciphey/commits?author=cyclic3" title="Code">💻</a> <a href="#ideas-cyclic3" title="Ideas, Planning, & Feedback">🤔</a></td>
    <td align="center"><a href="https://skerritt.blog"><img src="https://avatars3.githubusercontent.com/u/10378052?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon</b></sub></a><br /><a href="#design-brandonskerritt" title="Design">🎨</a> <a href="#maintenance-brandonskerritt" title="Maintenance">🚧</a> <a href="https://github.com/Ciphey/Ciphey/commits?author=brandonskerritt" title="Code">💻</a> <a href="#ideas-brandonskerritt" title="Ideas, Planning, & Feedback">🤔</a></td>
    <td align="center"><a href="https://github.com/michalani"><img src="https://avatars0.githubusercontent.com/u/27767884?v=4?s=100" width="100px;" alt=""/><br /><sub><b>michalani</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=michalani" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/ashb07"><img src="https://avatars2.githubusercontent.com/u/24845568?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ashb07</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=ashb07" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/TheAlcanian"><img src="https://avatars3.githubusercontent.com/u/22127191?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shardion</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/issues?q=author%3ATheAlcanian" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://github.com/Bryzizzle"><img src="https://avatars0.githubusercontent.com/u/57810197?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bryan</b></sub></a><br /><a href="#translation-Bryzizzle" title="Translation">🌍</a> <a href="https://github.com/Ciphey/Ciphey/commits?author=Bryzizzle" title="Documentation">📖</a></td>
    <td align="center"><a href="https://lukasgabriel.net"><img src="https://avatars0.githubusercontent.com/u/52338810?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Gabriel</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=lukasgabriel" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3Alukasgabriel" title="Bug reports">🐛</a> <a href="#translation-lukasgabriel" title="Translation">🌍</a> <a href="#ideas-lukasgabriel" title="Ideas, Planning, & Feedback">🤔</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/DarshanBhoi"><img src="https://avatars2.githubusercontent.com/u/70128281?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Darshan</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/issues?q=author%3ADarshanBhoi" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://github.com/SkeletalDemise"><img src="https://avatars1.githubusercontent.com/u/29117662?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SkeletalDemise</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=SkeletalDemise" title="Code">💻</a></td>
    <td align="center"><a href="https://www.patreon.com/cclauss"><img src="https://avatars3.githubusercontent.com/u/3709715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Clauss</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=cclauss" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3Acclauss" title="Bug reports">🐛</a></td>
    <td align="center"><a href="http://machinexa.xss.ht"><img src="https://avatars1.githubusercontent.com/u/60662297?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Machinexa2</b></sub></a><br /><a href="#content-machinexa2" title="Content">🖋</a></td>
    <td align="center"><a href="https://github.com/anantverma275"><img src="https://avatars1.githubusercontent.com/u/18184503?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anant Verma</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=anantverma275" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3Aanantverma275" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://github.com/XVXTOR"><img src="https://avatars1.githubusercontent.com/u/40268197?v=4?s=100" width="100px;" alt=""/><br /><sub><b>XVXTOR</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=XVXTOR" title="Documentation">📖</a></td>
    <td align="center"><a href="https://github.com/Itamikame"><img src="https://avatars2.githubusercontent.com/u/59034423?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Itamikame</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=Itamikame" title="Code">💻</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/MikeMerz"><img src="https://avatars3.githubusercontent.com/u/50526795?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MikeMerz</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=MikeMerz" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/jacobggman"><img src="https://avatars2.githubusercontent.com/u/30216976?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob Galam</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=jacobggman" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3Ajacobggman" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://tuxthexplorer.github.io/"><img src="https://avatars1.githubusercontent.com/u/37508897?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TuxTheXplorer</b></sub></a><br /><a href="#translation-TuxTheXplorer" title="Translation">🌍</a></td>
    <td align="center"><a href="https://github.com/Itamai"><img src="https://avatars3.githubusercontent.com/u/53093696?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Itamai</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=Itamai" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3AItamai" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://github.com/Termack"><img src="https://avatars2.githubusercontent.com/u/26333901?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Filipe</b></sub></a><br /><a href="#translation-Termack" title="Translation">🌍</a></td>
    <td align="center"><a href="https://github.com/malathit"><img src="https://avatars0.githubusercontent.com/u/2684148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Malathi</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=malathit" title="Code">💻</a></td>
    <td align="center"><a href="https://hexchaos.xyz/"><img src="https://avatars1.githubusercontent.com/u/8947820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jack</b></sub></a><br /><a href="#translation-HexChaos" title="Translation">🌍</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/yafkari"><img src="https://avatars3.githubusercontent.com/u/41365655?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Younes</b></sub></a><br /><a href="#translation-yafkari" title="Translation">🌍</a></td>
    <td align="center"><a href="https://gitlab.com/Marnick39"><img src="https://avatars2.githubusercontent.com/u/17315511?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marnick Vandecauter</b></sub></a><br /><a href="#translation-Marnick39" title="Translation">🌍</a></td>
    <td align="center"><a href="https://github.com/mav8557"><img src="https://avatars0.githubusercontent.com/u/47306745?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael V</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=mav8557" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/chuinzer"><img src="https://avatars2.githubusercontent.com/u/64257785?v=4?s=100" width="100px;" alt=""/><br /><sub><b>chuinzer</b></sub></a><br /><a href="#translation-chuinzer" title="Translation">🌍</a></td>
    <td align="center"><a href="https://github.com/blackcat-917"><img src="https://avatars1.githubusercontent.com/u/53786619?v=4?s=100" width="100px;" alt=""/><br /><sub><b>blackcat-917</b></sub></a><br /><a href="#translation-blackcat-917" title="Translation">🌍</a> <a href="https://github.com/Ciphey/Ciphey/commits?author=blackcat-917" title="Documentation">📖</a></td>
    <td align="center"><a href="https://github.com/Ozzyz"><img src="https://avatars3.githubusercontent.com/u/6113447?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Åsmund Brekke</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=Ozzyz" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/sashreek1"><img src="https://avatars1.githubusercontent.com/u/45600974?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sashreek Shankar</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=sashreek1" title="Code">💻</a></td>
  </tr>
  <tr>
    <td align="center"><a href="https://github.com/cryptobadger"><img src="https://avatars2.githubusercontent.com/u/26308101?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cryptobadger</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=cryptobadger" title="Code">💻</a> <a href="https://github.com/Ciphey/Ciphey/issues?q=author%3Acryptobadger" title="Bug reports">🐛</a></td>
    <td align="center"><a href="https://github.com/e1fy"><img src="https://avatars3.githubusercontent.com/u/61194758?v=4?s=100" width="100px;" alt=""/><br /><sub><b>elf</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=e1fy" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/rogercyyu"><img src="https://avatars0.githubusercontent.com/u/45835736?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Roger Yu</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=rogercyyu" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/JesseEmond"><img src="https://avatars.githubusercontent.com/u/1843555?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dysleixa</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=JesseEmond" title="Code">💻</a></td>
    <td align="center"><a href="http://mohzulfikar.me"><img src="https://avatars.githubusercontent.com/u/48849323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohammad Zulfikar</b></sub></a><br /><a href="https://github.com/Ciphey/Ciphey/commits?author=mohzulfikar" title="Documentation">📖</a></td>
    <td align="center"><a href="https://github.com/AABur"><img src="https://avatars.githubusercontent.com/u/41373199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Burchenko</b></sub></a><br /><a href="#translation-AABur" title="Translation">🌍</a></td>
  </tr>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!


================================================
FILE: ciphey/__init__.py
================================================
from . import basemods, common, iface
from .ciphey import decrypt


================================================
FILE: ciphey/__main__.py
================================================
#! /usr/bin/env python3

"""
Ciphey: https://github.com/Ciphey/Ciphey
"""

import platform
import sys

if __name__ == "__main__":
    major = sys.version_info[0]
    minor = sys.version_info[1]

    python_version = (
        str(sys.version_info[0])
        + "."
        + str(sys.version_info[1])
        + "."
        + str(sys.version_info[2])
    )

    if major != 3 or minor < 6:
        print(
            f"Ciphey requires Python 3.6+, you are using {python_version}. Please install a higher Python version. https://www.python.org/downloads/"
        )
        print(
            "Alternatively, visit our Discord and use the Ciphey bot in #bots http://discord.skerritt.blog"
        )
        sys.exit(1)
    if platform.system() == "Windows":
        if minor > 8:
            print(
                "Ciphey does not currently support Python 3.9 on Windows. Please use the Discord bot at http://discord.skerritt.blog"
            )
            sys.exit(1)

        if sys.maxsize > 2 ** 32 is False:
            print(
                "You are using Python 32 bit and Windows, Ciphey does not support this. Please upgrade to Python 64-bit here https://www.python.org/downloads/"
            )
            sys.exit(1)
    from .ciphey import main

    main()


================================================
FILE: ciphey/basemods/Checkers/__init__.py
================================================
from . import any, brandon, ezcheck, format, human, quadgrams, quorum, regex, what


================================================
FILE: ciphey/basemods/Checkers/any.py
================================================
from typing import Dict, Optional

from ciphey.iface import Config, ParamSpec, PolymorphicChecker, registry


@registry.register
class Any(PolymorphicChecker):
    """Should only be used for debugging, frankly"""

    def getExpectedRuntime(self, text) -> float:
        return 0  # TODO: actually calculate this

    def __init__(self, config: Config):
        super().__init__(config)

    def check(self, text: str) -> Optional[str]:
        return ""

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        pass


================================================
FILE: ciphey/basemods/Checkers/brandon.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: brandonskerritt

Class to determine whether something is English or not.
1. Calculate the Chi Squared score of a sentence
2. If the score is significantly lower than the average score, it _might_ be English
    2.1. If the score _might_ be English, then take the text and compare it to the sorted dictionary
    in O(n log n) time.
    It creates a percentage of "How much of this text is in the dictionary?"
    The dictionary contains:
        * 20,000 most common US words
        * 10,000 most common UK words (there's no repetition between the two)
        * The top 10,000 passwords
    If the word "Looks like" English (chi-squared) and if it contains English words, we can conclude it is
    very likely English. The alternative is doing the dictionary thing but with an entire 479k word dictionary (slower)
    2.2. If the score is not English, but we haven't tested enough to create an average, then test it against
     the dictionary

Things to optimise:
* We only run the dictionary if it's 20% smaller than the average for chi squared
* We consider it "English" if 45% of the text matches the dictionary
* We run the dictionary if there is less than 10 total chisquared test

How to add a language:
* Download your desired dictionary. Try to make it the most popular words, for example. Place this file into this
 folder with languagename.txt
As an example, this comes built in with english.txt
Find the statistical frequency of each letter in that language.
For English, we have:
self.languages = {
    "English":
    [0.0855, 0.0160, 0.0316, 0.0387, 0.1210,0.0218, 0.0209, 0.0496, 0.0733, 0.0022,0.0081, 0.0421, 0.0253, 0.0717,
    0.0747,0.0207, 0.0010, 0.0633, 0.0673, 0.0894,0.0268, 0.0106, 0.0183, 0.0019, 0.0172,0.0011]
}
In chisquared.py
To add your language, do:
self.languages = {
    "English":
    [0.0855, 0.0160, 0.0316, 0.0387, 0.1210,0.0218, 0.0209, 0.0496, 0.0733, 0.0022,0.0081, 0.0421, 0.0253, 0.0717,
    0.0747,0.0207, 0.0010, 0.0633, 0.0673, 0.0894,0.0268, 0.0106, 0.0183, 0.0019, 0.0172,0.0011]
    "German": [0.0973]
}
In alphabetical order
And you're.... Done! Make sure the name of the two match up
"""
import sys
from math import ceil
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Checker, Config, ParamSpec, T, registry

sys.path.append("..")
try:
    import mathsHelper as mh
except ModuleNotFoundError:
    import ciphey.mathsHelper as mh


@registry.register
class Brandon(Checker[str]):
    """
    Class designed to confirm whether something is **language** based on how many words of **language** appears
    Call confirmLanguage(text, language)
    * text: the text you want to confirm
    * language: the language you want to confirm

    Find out what language it is by using chisquared.py, the highest chisquared score is the language
    languageThreshold = 45
    if a string is 45% **language** words, then it's confirmed to be english
    """

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually work this out
        # TODO its 0.2 seconds on average
        return 1e-4  # 100 µs

    wordlist: set

    def clean_text(self, text: str) -> set:
        """Cleans the text ready to be checked

        Strips punctuation, makes it lower case, turns it into a set separated by spaces, removes duplicate words

        Args:
            text -> The text we use to perform analysis on

        Returns:
            text -> the text as a list, now cleaned

        """
        # makes the text unique words and readable
        text = text.lower()
        text = self.mh.strip_punctuation(text)
        text = text.split(" ")
        text = filter(lambda x: len(x) > 2, text)
        text = set(text)
        return text

    def checker(self, text: str, threshold: float, text_length: int, var: set) -> bool:
        """Given text determine if it passes checker

        The checker uses the variable passed to it. I.E. Stopwords list, 1k words, dictionary

        Args:
            text -> The text to check
            threshold -> at what point do we return True? The percentage of text that is in var before we return True
            text_length -> the length of the text
            var -> the variable we are checking against. Stopwords list, 1k words list, dictionary list.
        Returns:
            boolean -> True for it passes the test, False for it fails the test."""
        if text is None:
            logging.debug("Checker's text is None, so returning False")
            return False
        if var is None:
            logging.debug("Checker's input var is None, so returning False")
            return False

        percent = ceil(text_length * threshold)
        logging.debug(f"Checker's chunks are size {percent}")
        meet_threshold = 0
        location = 0
        end = percent

        if text_length <= 0:
            return False

        while location <= text_length:
            # chunks the text, so only gets THRESHOLD chunks of text at a time
            text = list(text)
            to_analyse = text[location:end]
            logging.debug(f"To analyse is {to_analyse}")
            for word in to_analyse:
                # if word is a stopword, + 1 to the counter
                if word in var:
                    logging.debug(
                        f"{word} is in var, which means I am +=1 to the meet_threshold which is {meet_threshold}"
                    )
                    meet_threshold += 1
                meet_threshold_percent = meet_threshold / text_length
                if meet_threshold_percent >= threshold:
                    logging.debug(
                        f"Returning true since the percentage is {meet_threshold / text_length} and the threshold is {threshold}"
                    )
                    # if we meet the threshold, return True
                    # otherwise, go over again until we do
                    # We do this in the for loop because if we're at 24% and THRESHOLD is 25
                    # we don't want to wait THRESHOLD to return true, we want to return True ASAP
                    return True
            location = end
            end = end + percent
        logging.debug(
            f"The language proportion {meet_threshold_percent} is under the threshold {threshold}"
        )
        return False

    def __init__(self, config: Config):
        # Suppresses warning
        super().__init__(config)
        self.mh = mh.mathsHelper()

        phases = config.get_resource(self._params()["phases"])

        self.thresholds_phase1 = phases["1"]
        self.thresholds_phase2 = phases["2"]
        self.top1000Words = config.get_resource(self._params().get("top1000"))
        self.wordlist = config.get_resource(self._params()["wordlist"])
        self.stopwords = config.get_resource(self._params().get("stopwords"))

        self.len_phase1 = len(self.thresholds_phase1)
        self.len_phase2 = len(self.thresholds_phase2)

    def check(self, text: str) -> Optional[str]:
        """Checks to see if the text is in English

        Performs a decryption, but mainly parses the internal data packet and prints useful information.

        Args:
            text -> The text we use to perform analysis on

        Returns:
            bool -> True if the text is English, False otherwise.

        """
        logging.debug(f'In Language Checker with "{text}"')
        text = self.clean_text(text)
        logging.debug(f'Text split to "{text}"')
        if text == "":
            logging.debug("Returning None from Brandon as the text cleaned is none.")
            return None

        length_text = len(text)

        what_to_use = {}

        # this code decides what checker / threshold to use
        # if text is over or equal to maximum size, just use the maximum possible checker
        what_to_use = self.calculateWhatChecker(
            length_text, self.thresholds_phase1.keys()
        )
        logging.debug(self.thresholds_phase1)
        what_to_use = self.thresholds_phase1[str(what_to_use)]
        # def checker(self, text: str, threshold: float, text_length: int, var: set) -> bool:
        if "check" in what_to_use:
            # perform check 1k words
            result = self.checker(
                text, what_to_use["check"], length_text, self.top1000Words
            )
        elif "stop" in what_to_use:
            # perform stopwords
            result = self.checker(
                text, what_to_use["stop"], length_text, self.stopwords
            )
        elif "dict" in what_to_use:
            result = self.checker(text, what_to_use["dict"], length_text, self.wordlist)
            # If result is None, no point doing it again in phase2
            if not result:
                return None
        else:
            logging.info(f"It is neither stop or check, but instead {what_to_use}")

        # return False if phase 1 fails
        if not result:
            return None
        else:
            what_to_use = self.calculateWhatChecker(
                length_text, self.thresholds_phase2.keys()
            )
            what_to_use = self.thresholds_phase2[str(what_to_use)]
            result = self.checker(text, what_to_use["dict"], length_text, self.wordlist)
        return "" if result else None

    def calculateWhatChecker(self, length_text, key):
        """Calculates what threshold / checker to use

        If the length of the text is over the maximum sentence length, use the last checker / threshold
        Otherwise, traverse the keys backwards until we find a key range that does not fit.
        So we traverse backwards and see if the sentence length is between current - 1 and current
        In this way, we find the absolute lowest checker / percentage threshold.
        We traverse backwards because if the text is longer than the max sentence length, we already know.
        In total, the keys are only 5 items long or so. It is not expensive to move backwards, nor is it expensive to move forwards.

        Args:
            length_text -> The length of the text
            key -> What key we want to use. I.E. Phase1 keys, Phase2 keys.
        Returns:
            what_to_use -> the key of the lowest checker."""

        _keys = list(key)
        _keys = list(map(int, _keys))
        if length_text >= int(_keys[-1]):
            what_to_use = list(key)[_keys.index(_keys[-1])]
        else:
            # this algorithm finds the smallest possible fit for the text
            for counter, i in reversed(list(enumerate(_keys))):
                #  [0, 110, 150]
                if i <= length_text:
                    what_to_use = i
        return what_to_use

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "top1000": ParamSpec(
                desc="A wordlist of the top 1000 words",
                req=False,
                default="cipheydists::list::english1000",
            ),
            "wordlist": ParamSpec(
                desc="A wordlist of all the words",
                req=False,
                default="cipheydists::list::english",
            ),
            "stopwords": ParamSpec(
                desc="A wordlist of StopWords",
                req=False,
                default="cipheydists::list::englishStopWords",
            ),
            "threshold": ParamSpec(
                desc="The minimum proportion (between 0 and 1) that must be in the dictionary",
                req=False,
                default=0.45,
            ),
            "phases": ParamSpec(
                desc="Language-specific phase thresholds",
                req=False,
                default="cipheydists::brandon::english",
            ),
        }


================================================
FILE: ciphey/basemods/Checkers/entropy.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Checker, Config, ParamSpec, T, registry


@registry.register
class Entropy(Checker[str]):

    """
    Uses entropy to determine plaintext
    """

    def check(self, text: T) -> Optional[str]:
        logging.debug("Trying entropy checker")
        pass

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually bench this
        # Uses benchmark from Discord
        return 2e-7 * len(text)

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        pass


================================================
FILE: ciphey/basemods/Checkers/ezcheck.py
================================================
from typing import Dict, List, Optional

from ciphey.iface import Checker, Config, ParamSpec, T, registry

from .brandon import Brandon
from .format import JsonChecker
from .human import HumanChecker
from .quadgrams import Quadgrams
from .regex import RegexList
from .what import What


@registry.register
class EzCheck(Checker[str]):
    """
    This object is effectively a prebuilt quorum (with requirement 1) of common patterns, followed by a human check
    """

    def check(self, text: str) -> Optional[str]:
        for checker in self.checkers:
            res = checker.check(text)
            if (
                res is not None
                and (self.decider is None or self.decider.check(text)) is not None
            ):
                return res
        return None

    def getExpectedRuntime(self, text: T) -> float:
        return sum(
            i.getExpectedRuntime(text) for i in self.checkers
        ) + self.decider.getExpectedRuntime(text)

    def __init__(self, config: Config):
        super().__init__(config)

        self.checkers: List[Checker[str]] = []
        # Disable human checker for automated systems
        if config.verbosity >= 0:
            self.decider = config(HumanChecker)
        else:
            self.decider = None

        # We need to modify the config for each of the objects

        # First PyWhat, as it's the fastest
        self.checkers.append(config(What))

        # Next, the json checker
        self.checkers.append(config(JsonChecker))

        # Second to last, the quadgrams checker
        self.checkers.append(config(Quadgrams))

        # Finally, the Brandon checker, as it is the slowest
        self.checkers.append(config(Brandon))

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        pass


================================================
FILE: ciphey/basemods/Checkers/format.py
================================================
import json
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Checker, Config, ParamSpec, T, registry


@registry.register
class JsonChecker(Checker[str]):

    """
    This object is effectively a prebuilt quorum (with requirement 1) of common patterns
    """

    def check(self, text: T) -> Optional[str]:
        logging.debug("Trying json checker")

        # https://github.com/Ciphey/Ciphey/issues/389
        if text.isdigit():
            return None

        try:
            json.loads(text)
            return ""
        except ValueError:
            return None

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually bench this
        return 1e-7 * len(text)  # From benchmarks I found online

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        pass


================================================
FILE: ciphey/basemods/Checkers/gtest.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Checker, Config, ParamSpec, T, registry


@registry.register
class GTestChecker(Checker[str]):

    """
    G-test of fitness, similar to Chi squared.
    """

    def check(self, text: T) -> Optional[str]:
        logging.debug("Trying entropy checker")
        pass

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually bench this
        return 4e-7 * len(text)

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        pass


================================================
FILE: ciphey/basemods/Checkers/human.py
================================================
from typing import Dict, Optional

from ciphey.iface import Checker, Config, ParamSpec, registry
from rich.console import Console
from rich.markup import escape

console = Console()


@registry.register
class HumanChecker(Checker[str]):

    """
    Uses the person's decision to determine plaintext
    """

    def check(self, ctext: str) -> Optional[str]:
        with self._config().pause_spinner_handle():
            response = console.input(
                f"Possible plaintext: [blue bold]{escape(ctext.__repr__())}[/blue bold] ([green]y[/green]/[red]N[/red]): "
            )
        if response == "y":
            return ""
        elif response in ("n", ""):
            return None
        else:
            return self.check(ctext)

    def getExpectedRuntime(self, text: str) -> float:
        return 1  # About a second

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    def __init__(self, config: Config):
        super().__init__(config)


================================================
FILE: ciphey/basemods/Checkers/quadgrams.py
================================================
import logging
import re
from math import log10
from typing import Dict, Optional

from ciphey.iface import Checker, Config, ParamSpec, T, Translation, registry
from rich.logging import RichHandler


@registry.register
class Quadgrams(Checker[str]):

    """
    Uses Quadgrams to determine plaintext
    """

    def check(self, ctext: T) -> Optional[str]:
        logging.debug("Trying Quadgrams checker")
        # Capitalize and remove everything that's not a letter
        ctext = re.sub("[^A-Z]", "", ctext.upper())
        quadgrams = self.QUADGRAMS_DICT
        quadgrams_sum = sum(quadgrams.values())
        score = 0
        for key in quadgrams.keys():
            quadgrams[key] = float(quadgrams[key]) / quadgrams_sum
        floor = log10(0.01 / quadgrams_sum)
        for i in range(len(ctext) - 4 + 1):
            # Get all quadgrams from ctext and check if they're in the dict
            # If yes then add the score of those quadgrams to the total score
            if ctext[i : i + 4] in quadgrams:
                score += quadgrams[ctext[i : i + 4]]
            else:
                score += floor
        if len(ctext) > 0:
            score = score / len(ctext)
        logging.info(f"Quadgrams is {score}")
        # The default threshold was found to work the best from lots of testing
        if score > self.threshold:
            return ""
        return None

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually bench this
        return 2e-7 * len(text)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The quadgrams dictionary to use",
                req=False,
                default="cipheydists::dist::quadgrams",
            ),
            "score": ParamSpec(
                desc="The score threshold to use",
                req=False,
                default=0.00011,
            ),
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.QUADGRAMS_DICT = config.get_resource(self._params()["dict"], Translation)
        self.threshold = float(self._params()["score"])


================================================
FILE: ciphey/basemods/Checkers/quorum.py
================================================
from typing import Dict, Generic, Optional

from ciphey.iface import Checker, Config, ParamSpec, T, _registry


class Quorum(Generic[T], Checker[T]):
    def check(self, text: T) -> Optional[str]:
        left = self._params().k
        results = []
        for checker in self.checkers:
            results.append(checker.check(text))
            if results[-1] is None:
                continue
            left -= 1
            # Early return check
            if left == 0:
                return str(results)

    def __init__(self, config: Config):
        super().__init__(config)

        if self._params().k is None:
            k = len(self._params()["checker"])
        # These checks need to be separate, to make sure that we do not have zero members
        if self._params().k == 0 or self._params().k > len(self._params()["checker"]):
            raise IndexError(
                "k must be between 0 and the number of checkers (inclusive)"
            )

        self.checkers = []
        for i in self._params()["checker"]:
            # This enforces type consistency
            self.checkers.append(_registry.get_named(i, Checker[T]))

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "checker": ParamSpec(
                req=True, desc="The checkers to be used for analysis", list=True
            ),
            "k": ParamSpec(
                req=False,
                desc="The minimum quorum size. Defaults to the number of checkers",
            ),
        }


================================================
FILE: ciphey/basemods/Checkers/regex.py
================================================
import re
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Checker, Config, ParamSpec, T, registry


@registry.register
class Regex(Checker[str]):
    def getExpectedRuntime(self, text: T) -> float:
        return 1e-5  # TODO: actually calculate this

    def __init__(self, config: Config):
        super().__init__(config)
        self.regexes = list(map(re.compile, self._params()["regex"]))
        logging.debug(f"There are {len(self.regexes)} regexes")

    def check(self, text: str) -> Optional[str]:
        for regex in self.regexes:
            logging.debug(f"Trying regex {regex} on {text}")
            res = regex.search(text)
            logging.debug(f"Results: {res}")
            if res:
                return f"Passed with regex {regex}. Want to contribute to Ciphey? Submit your regex here to allow Ciphey to automatically get this next time https://github.com/bee-san/pyWhat/wiki/Adding-your-own-Regex\n"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "regex": ParamSpec(
                req=True,
                desc="The regex that must be matched (in a substring)",
                list=True,
            )
        }


@registry.register
class RegexList(Checker[str]):
    def getExpectedRuntime(self, text: T) -> float:
        return 1e-5  # TODO: actually calculate this

    def __init__(self, config: Config):
        super().__init__(config)
        self.regexes = []
        for i in self._params()["resource"]:
            self.regexes += [re.compile(regex) for regex in config.get_resource(i)]
        logging.debug(f"There are {len(self.regexes)} regexes")

    def check(self, text: str) -> Optional[str]:
        for regex in self.regexes:
            logging.debug(f"Trying regex {regex} on {text}")
            res = regex.search(text)
            logging.debug(f"Results: {res}")
            if res:
                return f"passed with regex {regex}"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "resource": ParamSpec(
                req=True,
                desc="A list of regexes that could be matched",
                list=True,
            )
        }


================================================
FILE: ciphey/basemods/Checkers/what.py
================================================
from typing import Dict, Optional

from ciphey.iface import Checker, Config, ParamSpec, T, registry
import logging
from rich.logging import RichHandler
from pywhat import identifier
from rich.console import Console

console = Console()


@registry.register
class What(Checker[str]):

    """
    Uses PyWhat to determine plaintext with regexes
    https://github.com/bee-san/pyWhat
    """

    def check(self, ctext: T) -> Optional[str]:
        logging.debug("Trying PyWhat checker")
        returned_regexes = self.id.identify(ctext)
        if returned_regexes["Regexes"]:
            matched_regex = returned_regexes["Regexes"]['text'][0]["Regex Pattern"]

            ret = f'The plaintext is a [yellow]{matched_regex["Name"]}[/yellow]'
            human = (
                f'\nI think the plaintext is a [yellow]{matched_regex["Name"]}[/yellow]'
            )

            if "Description" in matched_regex and matched_regex["Description"]:
                s = matched_regex["Description"]
                # lowercases first letter so it doesn't look weird
                s = f", which is {s[0].lower() + s[1:]}\n"
                ret += s
                human += s

            # if URL is attached, include that too.
            if "URL" in matched_regex and matched_regex["URL"]:
                link = matched_regex["URL"] + ctext.replace(" ", "")
                ret += f"\nClick here to view in browser [#CAE4F1][link={link}]{link}[/link][/#CAE4F1]\n"

            # If greppable mode is on, don't print this
            if self.config.verbosity >= 0:
                # Print with full stop
                console.print(human)
            return ret
        return None

    def getExpectedRuntime(self, text: T) -> float:
        # TODO: actually bench this
        return 2e-7 * len(text)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    def __init__(self, config: Config):
        super().__init__(config)
        self.config = config
        self.id = identifier.Identifier()


================================================
FILE: ciphey/basemods/Crackers/__init__.py
================================================
from . import (
    affine,
    ascii_shift,
    baconian,
    caesar,
    rot47,
    soundex,
    vigenere,
    xandy,
    xortool,
)


================================================
FILE: ciphey/basemods/Crackers/affine.py
================================================
# Community
# by https://github.com/Ozzyz

from typing import Dict, List, Optional

import cipheycore
import logging
from rich.logging import RichHandler

from ciphey.common import fix_case
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
from ciphey.mathsHelper import mathsHelper


@registry.register
class Affine(Cracker[str]):
    """
    Each character in the Affine Cipher is encoded with the rule E(x) = (ax + b) mod m
    m is the size of the alphabet, while a and b are the keys in the cipher. a must be coprime to b.
    The Caesar cipher is a specific case of the Affine Cipher, with a=1 and b being the shift of the cipher.
    Decryption is performed by D(x) = a_inv (x - b) mod m where a_inv is the modular multiplicative inverse of a mod m.

    In this version of the Affine Cipher, we do not allow alphabets with several instances of the same letter in different cases.
    For instance, the alphabet 'ABCdef123' is allowed, but 'AaBbCc' is not.
    """

    def getInfo(self, ctext: str) -> CrackInfo:
        return CrackInfo(
            success_likelihood=0.1,
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "affine"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        """
        Brute forces all the possible combinations of a and b to attempt to crack the cipher.
        """
        logging.debug("Attempting affine")
        candidates = []

        # a and b are coprime if gcd(a,b) is 1.
        possible_a = [
            a
            for a in range(1, self.alphabet_length)
            if mathsHelper.gcd(a, self.alphabet_length) == 1
        ]
        logging.info(
            f"Trying Affine Cracker with {len(possible_a)} a-values and {self.alphabet_length} b-values"
        )

        for a in possible_a:
            a_inv = mathsHelper.mod_inv(a, self.alphabet_length)
            # If there is no inverse, we cannot decrypt the text
            if a_inv is None:
                continue
            for b in range(self.alphabet_length):
                # Pass in lowered text. This means that we expect alphabets to not contain both 'a' and 'A'.
                translated = self.decrypt(ctext.lower(), a_inv, b, self.alphabet_length)

                candidate_probability = self.plaintext_probability(translated)
                if candidate_probability > self.plaintext_prob_threshold:
                    candidates.append(
                        CrackResult(
                            value=fix_case(translated, ctext), key_info=f"a={a}, b={b}"
                        )
                    )
        logging.info(f"Affine Cipher returned {len(candidates)} candidates")
        return candidates

    def plaintext_probability(self, translated: str) -> float:
        """
        Analyses the translated text and applies the chi squared test to see if it is a probable plaintext candidate
        Returns the probability of the chi-squared test.
        """
        analysis = cipheycore.analyse_string(translated)
        return cipheycore.chisq_test(analysis, self.expected)

    def decrypt(self, text: str, a_inv: int, b: int, m: int) -> str:
        """
        Each letter is decrypted at D(x) = a_inv (x - b) mod m where x is the char
        We treat the char value as its index in the alphabet, so if
        the alphabet is 'abcd....' and the char is 'b', it has the value 1.
        """
        return "".join([self.decryptChar(char, a_inv, b, m) for char in text])

    def decryptChar(self, char: str, a_inv: int, b: int, m: int) -> str:

        # We lower the alphabet since both ctext and alphabet need to be in the same case in order
        # to perform the shifts. The translated text will have fixed case after the translation anyways.
        # This is only necessary if the specified alphabet is uppercase.
        alphabet = [x.lower() for x in self.group]

        # Preserve characters that are not in alphabet
        if char not in alphabet:
            return char
        char_idx = alphabet.index(char)
        decrypted_char_idx = (a_inv * (char_idx - b)) % m
        return alphabet[decrypted_char_idx]

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "group": ParamSpec(
                desc="An ordered sequence of chars that make up the alphabet",
                req=False,
                default="abcdefghijklmnopqrstuvwxyz",
            ),
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.group = list(self._params()["group"])
        self.expected = config.get_resource(self._params()["expected"])
        self.alphabet_length = len(self.group)
        self.cache = config.cache
        self.plaintext_prob_threshold = 0.01


================================================
FILE: ciphey/basemods/Crackers/ascii_shift.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: brandonskerritt
"""

from typing import Dict, List, Optional

import cipheycore
import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class Ascii_shift(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )

        return CrackInfo(
            success_likelihood=cipheycore.caesar_detect(analysis, self.expected),
            # TODO: actually calculate runtimes
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "ascii_shift"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        logging.info(f"Trying ASCII shift cipher on {ctext}")

        logging.debug("Beginning cipheycore simple analysis")

        # Hand it off to the core
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )
        logging.debug("Beginning cipheycore::caesar")
        possible_keys = cipheycore.caesar_crack(
            analysis, self.expected, self.group, self.p_value
        )

        n_candidates = len(possible_keys)
        logging.info(f"ASCII shift returned {n_candidates} candidates")

        if n_candidates == 0:
            logging.debug("Filtering for better results")
            analysis = cipheycore.analyse_string(ctext, self.group)
            possible_keys = cipheycore.caesar_crack(
                analysis, self.expected, self.group, self.p_value
            )

        candidates = []

        for candidate in possible_keys:
            logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}")
            translated = cipheycore.caesar_decrypt(ctext, candidate.key, self.group)
            candidates.append(CrackResult(value=translated, key_info=candidate.key))

        return candidates

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "group": ParamSpec(
                desc="An ordered sequence of chars that make up the ASCII shift cipher alphabet",
                req=False,
                default="""\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f""",
            ),
            "p_value": ParamSpec(
                desc="The p-value to use for standard frequency analysis",
                req=False,
                default=0.01,
            )
            # TODO: add "filter" param
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.group = list(self._params()["group"])
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache
        self.p_value = float(self._params()["p_value"])


================================================
FILE: ciphey/basemods/Crackers/baconian.py
================================================
import re
from typing import Dict, List, Optional

from ciphey.iface import (
    Config,
    Cracker,
    CrackInfo,
    CrackResult,
    ParamSpec,
    Translation,
    registry,
)
import logging
from rich.logging import RichHandler


@registry.register
class Baconian(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        return CrackInfo(
            success_likelihood=0.1,
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "baconian"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        """
        Attempts to decode both variants of the Baconian cipher.
        """
        logging.debug("Attempting Baconian cracker")
        candidates = []
        result = []
        ctext_decoded = ""
        ctext_decoded2 = ""

        # Convert to uppercase and replace delimiters and whitespace with nothing
        ctext = re.sub(r"[,;:\-\s]", "", ctext.upper())

        # Make sure ctext only contains A and B
        if bool(re.search(r"[^AB]", ctext)) is True:
            logging.debug("Failed to crack baconian due to non baconian character(s)")
            return None

        # Make sure ctext is divisible by 5
        ctext_len = len(ctext)
        if ctext_len % 5:
            logging.debug(
                f"Failed to decode Baconian because length must be a multiple of 5, not '{ctext_len}'"
            )
            return None

        # Split ctext into groups of 5
        ctext = " ".join(ctext[i : i + 5] for i in range(0, len(ctext), 5))
        ctext_split = ctext.split(" ")
        baconian_keys = self.BACONIAN_DICT.keys()

        # Decode I=J and U=V variant
        for i in ctext_split:
            if i in baconian_keys:
                ctext_decoded += self.BACONIAN_DICT[i]

        # Decode variant that assigns each letter a unique code
        for i in ctext_split:
            if "+" + i in baconian_keys:
                ctext_decoded2 += self.BACONIAN_DICT["+" + i]

        candidates.append(ctext_decoded)
        candidates.append(ctext_decoded2)
        for candidate in candidates:
            if candidate != "":
                if candidate == candidates[0]:
                    result.append(CrackResult(value=candidate, key_info="I=J & U=V"))
                else:
                    result.append(CrackResult(value=candidate))
        logging.debug(f"Baconian cracker - Returning results: {result}")
        return result

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "dict": ParamSpec(
                desc="The Baconian alphabet dictionary to use",
                req=False,
                default="cipheydists::translate::baconian",
            ),
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.BACONIAN_DICT = config.get_resource(self._params()["dict"], Translation)
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache


================================================
FILE: ciphey/basemods/Crackers/caesar.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: brandonskerritt
"""
from distutils import util
from typing import Dict, List, Optional, Union

import cipheycore
import logging
from rich.logging import RichHandler

from ciphey.common import fix_case
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class Caesar(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )

        return CrackInfo(
            success_likelihood=cipheycore.caesar_detect(analysis, self.expected),
            # TODO: actually calculate runtimes
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "caesar"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        logging.info(f"Trying caesar cipher on {ctext}")
        # Convert it to lower case
        #
        # TODO: handle different alphabets
        if self.lower:
            message = ctext.lower()
        else:
            message = ctext

        logging.debug("Beginning cipheycore simple analysis")

        # Hand it off to the core
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )
        logging.debug("Beginning cipheycore::caesar")
        possible_keys = cipheycore.caesar_crack(
            analysis, self.expected, self.group, self.p_value
        )

        n_candidates = len(possible_keys)
        logging.info(f"Caesar returned {n_candidates} candidates")

        if n_candidates == 0:
            logging.debug("Filtering for better results")
            analysis = cipheycore.analyse_string(ctext, self.group)
            possible_keys = cipheycore.caesar_crack(
                analysis, self.expected, self.group, self.p_value
            )

        candidates = []

        for candidate in possible_keys:
            logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}")
            translated = cipheycore.caesar_decrypt(message, candidate.key, self.group)
            candidates.append(
                CrackResult(value=fix_case(translated, ctext), key_info=candidate.key)
            )

        return candidates

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "group": ParamSpec(
                desc="An ordered sequence of chars that make up the caesar cipher alphabet",
                req=False,
                default="abcdefghijklmnopqrstuvwxyz",
            ),
            "lower": ParamSpec(
                desc="Whether or not the ciphertext should be converted to lowercase first",
                req=False,
                default=True,
            ),
            "p_value": ParamSpec(
                desc="The p-value to use for standard frequency analysis",
                req=False,
                default=0.01,
            )
            # TODO: add "filter" param
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.lower: Union[str, bool] = self._params()["lower"]
        if not isinstance(self.lower, bool):
            self.lower = util.strtobool(self.lower)
        self.group = list(self._params()["group"])
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache
        self.p_value = float(self._params()["p_value"])


================================================
FILE: ciphey/basemods/Crackers/hash.py
================================================
"""
This is Hashbuster but slightly modified to work with Ciphey.
Why reinvent the wheel?
Changes (that I can remember)
* timeout set, as hashbuster took AGES before timeout was set.
https://github.com/s0md3v/Hash-Buster
"""

import re
from typing import Dict, List, Optional

import requests
import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, T, registry

thread_count = 4


def alpha(ctext, hashtype):
    return None


def beta(ctext, hashtype):
    try:
        response = requests.get(
            "https://hashtoolkit.com/reverse-hash/?hash=", ctext, timeout=5
        ).text
    except requests.exceptions.ReadTimeout as e:
        logging.info(f"Beta failed timeout {e}")
    match = re.search(r'/generate-hash/?text=.*?"', response)
    if match:
        return match.group(1)
    return None


def gamma(ctext, hashtype):
    try:
        response = requests.get(
            "https://www.nitrxgen.net/md5db/" + ctext, timeout=5
        ).text
    except requests.exceptions.ReadTimeout as e:
        logging.info(f"Gamma failed with {e}")
    if response:
        return response
    else:
        return None


def delta(ctext, hashtype):
    return None


def theta(ctext, hashtype):
    try:
        response = requests.get(
            "https://md5decrypt.net/Api/api.php?hash=%s&hash_type=%s&email=deanna_abshire@proxymail.eu&code=1152464b80a61728"
            % (ctext, hashtype),
            timeout=5,
        ).text
    except requests.exceptions.ReadTimeout as e:
        logging.info(f"Gamma failed with {e}")
    if len(response) != 0:
        return response
    else:
        return None


md5 = [gamma, alpha, beta, theta, delta]
sha1 = [alpha, beta, theta, delta]
sha256 = [alpha, beta, theta]
sha384 = [alpha, beta, theta]
sha512 = [alpha, beta, theta]


result = {}


def crack(ctext):
    raise "Error Crack is called"


def threaded(ctext):
    resp = crack(ctext)
    if resp:
        print(ctext + " : " + resp)
        result[ctext] = resp


@registry.register
class HashBuster(Cracker[str]):
    @staticmethod
    def getTarget() -> str:
        return "hash"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def priority() -> float:
        return 0.05

    def getInfo(self, ctext: T) -> CrackInfo:
        # TODO calculate these properly
        return CrackInfo(
            success_likelihood=0.5,
            success_runtime=5,
            failure_runtime=5,
        )

    def attemptCrack(self, ctext: T) -> List[CrackResult]:
        logging.info("Starting to crack hashes")
        result = False

        candidates = []
        if len(ctext) == 32:
            for api in md5:
                r = api(ctext, "md5")
                if result is not None or r is not None:
                    logging.debug("MD5 returns True {r}")
                    candidates.append(result, "MD5")
        elif len(ctext) == 40:
            for api in sha1:
                r = api(ctext, "sha1")
                if result is not None and r is not None:
                    logging.debug("sha1 returns true")
                    candidates.append(result, "SHA1")
        elif len(ctext) == 64:
            for api in sha256:
                r = api(ctext, "sha256")
                if result is not None and r is not None:
                    logging.debug("sha256 returns true")
                    candidates.append(result, "SHA256")
        elif len(ctext) == 96:
            for api in sha384:
                r = api(ctext, "sha384")
                if result is not None and r is not None:
                    logging.debug("sha384 returns true")
                    candidates.append(result, "SHA384")
        elif len(ctext) == 128:
            for api in sha512:
                r = api(ctext, "sha512")
                if result is not None and r is not None:
                    logging.debug("sha512 returns true")
                    candidates.append(result, "SHA512")

        # TODO what the fuck is this code?
        logging.debug(f"Hash buster returning {result}")
        # TODO add to 5.1 make this return multiple possible candidates
        return [CrackResult(value=candidates[0][0], misc_info=candidates[1][1])]

    def __init__(self, config: Config):
        super().__init__(config)


================================================
FILE: ciphey/basemods/Crackers/rot47.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: brandonskerritt
"""

from typing import Dict, List, Optional

import cipheycore
import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class Rot47(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )

        return CrackInfo(
            success_likelihood=cipheycore.caesar_detect(analysis, self.expected),
            # TODO: actually calculate runtimes
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "rot47"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        logging.info(f"Trying ROT47 cipher on {ctext}")

        logging.debug("Beginning cipheycore simple analysis")

        # Hand it off to the core
        analysis = self.cache.get_or_update(
            ctext,
            "cipheycore::simple_analysis",
            lambda: cipheycore.analyse_string(ctext),
        )
        logging.debug("Beginning cipheycore::caesar")
        possible_keys = cipheycore.caesar_crack(
            analysis, self.expected, self.group, self.p_value
        )

        n_candidates = len(possible_keys)
        logging.info(f"ROT47 returned {n_candidates} candidates")

        if n_candidates == 0:
            logging.debug("Filtering for better results")
            analysis = cipheycore.analyse_string(ctext, self.group)
            possible_keys = cipheycore.caesar_crack(
                analysis, self.expected, self.group, self.p_value
            )

        candidates = []

        for candidate in possible_keys:
            logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}")
            translated = cipheycore.caesar_decrypt(ctext, candidate.key, self.group)
            candidates.append(CrackResult(value=translated, key_info=candidate.key))

        return candidates

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "group": ParamSpec(
                desc="An ordered sequence of chars that make up the ROT47 cipher alphabet",
                req=False,
                default="""!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~""",
            ),
            "p_value": ParamSpec(
                desc="The p-value to use for standard frequency analysis",
                req=False,
                default=0.01,
            )
            # TODO: add "filter" param
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.group = list(self._params()["group"])
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache
        self.p_value = float(self._params()["p_value"])


================================================
FILE: ciphey/basemods/Crackers/soundex.py
================================================
import re
from typing import Dict, List, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import (
    Config,
    Cracker,
    CrackInfo,
    CrackResult,
    ParamSpec,
    Translation,
    registry,
)


@registry.register
class Soundex(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        return CrackInfo(
            success_likelihood=0.1,
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def getTarget() -> str:
        return "soundex"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        """
        Attempts to crack Soundex by generating all possible combinations.
        """
        logging.debug("Attempting Soundex cracker")
        word_list = []
        sentences = []
        result = []

        # Convert to uppercase and replace delimiters and whitespace with nothing
        ctext = re.sub(r"[,;:\-\s]", "", ctext.upper())

        # Make sure ctext contains only A-Z and 0-9
        if bool(re.search(r"[^A-Z0-9]", ctext)) is True:
            logging.debug("Failed to crack soundex due to non soundex character(s)")
            return None

        # Make sure ctext is divisible by 4
        ctext_len = len(ctext)
        if ctext_len % 4:
            logging.debug(
                f"Failed to decode Soundex because length must be a multiple of 4, not '{ctext_len}'"
            )
            return None

        # Split ctext into groups of 4
        ctext = " ".join(ctext[i : i + 4] for i in range(0, len(ctext), 4))
        ctext_split = ctext.split(" ")
        soundex_keys = self.SOUNDEX_DICT.keys()

        # Find all words that correspond to each given soundex code
        for code in ctext_split:
            if code in soundex_keys:
                word_list.append(self.SOUNDEX_DICT[code])

        logging.info(f"Possible words for given encoded text: {word_list}")

        # Find all possible sentences
        self.getSentenceCombo(
            word_list,
            sentences,
            self.frequency_dict,
            self.sentence_freq,
            self.word_freq,
        )

        sorted_sentences = self.sortlistwithdict(sentences, self.frequency_dict)

        for sentence in sorted_sentences:
            result.append(CrackResult(value=sentence))

        logging.debug(f"Soundex cracker - Returning results: {result}")
        return result

    def sortlistwithdict(self, listtosort, hashes):
        """
        This function uses the sum of ranks (based on frequency) of each word in each
        sentence and sorts them according to it.
        """
        return sorted(listtosort, key=lambda x: hashes[x])

    def getSentenceCombo(
        self, A, sentences, frequency_dict, sentence_freq, word_freq, result="", n=0
    ):
        """
        This function uses recursion to generate a list of sentences from all possible
        words for a given set of soundex codes.
        """
        logging.debug("Creating all possible sentences from Soundex")
        if n == len(A):
            sentences.append(result[1:])
            for word in result[1:].split():
                # Adding the rank of each word to find out the sentence's net frequency
                if word in word_freq:
                    sentence_freq += word_freq.index(word)
                # If the word isn't in the frequency list then it's a very uncommon word
                # so we add a large number (5000)
                else:
                    sentence_freq += 5000
            frequency_dict[result[1:]] = sentence_freq
            sentence_freq = 0
            return

        for word in A[n]:
            out = result + " " + word
            self.getSentenceCombo(
                A, sentences, frequency_dict, sentence_freq, word_freq, out, n + 1
            )

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The Soundex dictionary to use",
                req=False,
                default="cipheydists::translate::soundex",
            ),
            "freq": ParamSpec(
                desc="The word frequency dictionary to use",
                req=False,
                default="cipheydists::list::English5000Freq",
            ),
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.SOUNDEX_DICT = config.get_resource(self._params()["dict"], Translation)
        self.word_freq = config.get_resource(self._params()["freq"], Translation)
        self.frequency_dict = {}
        self.sentence_freq = 0


================================================
FILE: ciphey/basemods/Crackers/vigenere.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: brandonskerritt
"""
from distutils import util
from typing import Dict, List, Optional, Union

import cipheycore
import logging
from rich.logging import RichHandler

from ciphey.common import fix_case
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class Vigenere(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        if self.keysize is not None:
            analysis = self.cache.get_or_update(
                ctext,
                f"vigenere::{self.keysize}",
                lambda: cipheycore.analyse_string(
                    ctext.lower(), self.keysize, self.group
                ),
            )

            val = cipheycore.vigenere_detect(analysis, self.expected)

            logging.info(f"Vigenere has likelihood {val}")

            return CrackInfo(
                success_likelihood=val,
                # TODO: actually calculate runtimes
                success_runtime=1e-3,
                failure_runtime=1e-2,
            )

        likely_lens = self.cache.get_or_update(
            ctext,
            "vigenere::likely_lens",
            lambda: cipheycore.vigenere_likely_key_lens(
                ctext.lower(), self.expected, self.group, self.detect_p_value
            ),
        )

        # Filter out the lens that make no sense
        likely_lens = [i for i in likely_lens if i.len <= self.max_key_length]

        for keysize in likely_lens:
            # Store the analysis
            analysis = self.cache.get_or_update(
                ctext, f"vigenere::{keysize.len}", lambda: keysize.tab
            )
        if len(likely_lens) == 0:
            return CrackInfo(
                success_likelihood=0,
                # TODO: actually calculate runtimes
                success_runtime=2e-3,
                failure_runtime=2e-2,
            )

        logging.info(
            f"Vigenere has likelihood {likely_lens[0].p_value} with lens {[i.len for i in likely_lens]}"
        )

        return CrackInfo(
            success_likelihood=likely_lens[0].p_value,
            # TODO: actually calculate runtimes
            success_runtime=2e-4,
            failure_runtime=2e-4,
        )

    @staticmethod
    def getTarget() -> str:
        return "vigenere"

    def crackOne(
        self, ctext: str, analysis: cipheycore.windowed_analysis_res, real_ctext: str
    ) -> List[CrackResult]:
        possible_keys = cipheycore.vigenere_crack(
            analysis, self.expected, self.group, self.p_value
        )
        if len(possible_keys) > self.clamp:
            possible_keys = possible_keys[: self.clamp]
        logging.debug(
            f"Vigenere crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}"
        )
        return [
            CrackResult(
                value=fix_case(
                    cipheycore.vigenere_decrypt(ctext, candidate.key, self.group),
                    real_ctext,
                ),
                key_info="".join([self.group[i] for i in candidate.key]),
                misc_info=f"p-value was {candidate.p_value}",
            )
            for candidate in possible_keys[: min(len(possible_keys), 10)]
        ]

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        logging.info("Trying vigenere cipher")
        # Convert it to lower case
        if self.lower:
            message = ctext.lower()
        else:
            message = ctext

        # Analysis must be done here, where we know the case for the cache
        if self.keysize is not None:
            return self.crackOne(
                message,
                self.cache.get_or_update(
                    ctext,
                    f"vigenere::{self.keysize}",
                    lambda: cipheycore.analyse_string(
                        message, self.keysize, self.group
                    ),
                ),
                ctext,
            )

        arrs = []
        likely_lens = self.cache.get_or_update(
            ctext,
            "vigenere::likely_lens",
            lambda: cipheycore.vigenere_likely_key_lens(
                message, self.expected, self.group
            ),
        )
        possible_lens = [i for i in likely_lens]
        possible_lens.sort(key=lambda i: i.p_value)
        logging.debug(f"Got possible lengths {[i.len for i in likely_lens]}")
        # TODO: work out length
        for i in possible_lens:
            arrs.extend(
                self.crackOne(
                    message,
                    self.cache.get_or_update(
                        ctext,
                        f"vigenere::{i.len}",
                        lambda: cipheycore.analyse_string(message, i.len, self.group),
                    ),
                    ctext,
                )
            )

        logging.info(f"Vigenere returned {len(arrs)} candidates")
        return arrs

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "group": ParamSpec(
                desc="An ordered sequence of chars that make up the caesar cipher alphabet",
                req=False,
                default="abcdefghijklmnopqrstuvwxyz",
            ),
            "lower": ParamSpec(
                desc="Whether or not the ciphertext should be converted to lowercase first",
                req=False,
                default=True,
            ),
            "keysize": ParamSpec(
                desc="A key size that should be used. If not given, will attempt to work it out",
                req=False,
            ),
            "p_value": ParamSpec(
                desc="The p-value to use for windowed frequency analysis",
                req=False,
                default=0.5,
            ),
            "detect_p_value": ParamSpec(
                desc="The p-value to use for the detection of Vigenere length",
                req=False,
                default=0.01,
            ),
            "clamp": ParamSpec(
                desc="The maximum number of candidates that can be returned per key len",
                req=False,
                default=10,
            ),
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.lower: Union[str, bool] = self._params()["lower"]
        if not isinstance(self.lower, bool):
            self.lower = util.strtobool(self.lower)
        self.group = list(self._params()["group"])
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache
        self.keysize = self._params().get("keysize")
        if self.keysize is not None:
            self.keysize = int(self.keysize)
        self.p_value = float(self._params()["p_value"])
        self.detect_p_value = float(self._params()["detect_p_value"])
        self.clamp = int(self._params()["clamp"])
        self.max_key_length = 16


================================================
FILE: ciphey/basemods/Crackers/xandy.py
================================================
import re
from typing import Dict, List, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class Xandy(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        return CrackInfo(
            success_likelihood=0.1,
            success_runtime=1e-5,
            failure_runtime=1e-5,
        )

    @staticmethod
    def binary_to_ascii(variant):
        # Convert the binary string to an integer with base 2
        binary_int = int(variant, 2)
        byte_number = binary_int.bit_length() + 7 // 8

        # Convert the resulting int to a bytearray and then decode it to ASCII text
        binary_array = binary_int.to_bytes(byte_number, "big")
        try:
            ascii_text = binary_array.decode()
            logging.debug(f"Found possible solution: {ascii_text[:32]}")
            return ascii_text
        except UnicodeDecodeError as e:
            logging.debug(f"Failed to crack X-Y due to a UnicodeDecodeError: {e}")
            return ""

    @staticmethod
    def getTarget() -> str:
        return "xandy"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        """
        Checks an input if it only consists of two or three different letters.
        If this is the case, it attempts to regard those letters as
        0 and 1 (with the third characters as an optional delimiter) and then
        converts it to ASCII text.
        """
        logging.debug("Attempting X-Y replacement")
        variants = []
        candidates = []
        result = []

        # Convert the ctext to all-lowercase and regex-match & replace all whitespace
        ctext = re.sub(r"\s+", "", ctext.lower(), flags=re.UNICODE)

        # cset contains every unique value in the ctext
        cset = list(set(list(ctext)))
        cset_len = len(cset)

        if not 1 < cset_len < 4:
            # We only consider inputs with two or three unique values
            logging.debug(
                "Failed to crack X-Y due to not containing two or three unique values"
            )
            return None

        logging.debug(f"String contains {cset_len} unique values: {cset}")

        # In case of three unique values, we regard the least frequent character as the delimiter
        if cset_len == 3:
            # Count each unique character in the set to determine the least frequent one
            counting_list = []
            for char in cset:
                counting_list.append(ctext.count(char))
            val, index = min((val, index) for (index, val) in enumerate(counting_list))
            delimiter = cset[index]
            logging.debug(
                f"{delimiter} occurs {val} times and is the probable delimiter"
            )
            # Remove the delimiter from the ctext and compute new cset
            ctext = ctext.replace(delimiter, "")
            cset = list(set(list(ctext)))

        # Form both variants of the substitution
        for i in range(2):
            if i:
                variants.append(ctext.replace(cset[0], "1").replace(cset[1], "0"))
            else:
                variants.append(ctext.replace(cset[0], "0").replace(cset[1], "1"))

        # Apply function to both variants and strip stray NULL characters
        for variant in variants:
            candidates.append(self.binary_to_ascii(variant).strip("\x00"))
        for i, candidate in enumerate(candidates):
            if candidate != "":
                keyinfo = f"{cset[0]} -> {i} & {cset[1]} -> {str(int(not i))}"
                result.append(CrackResult(value=candidate, key_info=keyinfo))
                logging.debug(f"X-Y cracker - Returning results: {result}")
                return result

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            )
        }

    def __init__(self, config: Config):
        super().__init__(config)
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache


================================================
FILE: ciphey/basemods/Crackers/xortool.py
================================================
"""
 ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝
██║     ██║██████╔╝███████║█████╗   ╚████╔╝
██║     ██║██╔═══╝ ██╔══██║██╔══╝    ╚██╔╝
╚██████╗██║██║     ██║  ██║███████╗   ██║
© Brandon Skerritt
Github: bee-san
"""
from typing import Dict, List, Optional

import logging
from rich.logging import RichHandler

from xortool_ciphey import tool_main

from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry


@registry.register
class XorTool(Cracker[str]):
    def getInfo(self, ctext: str) -> CrackInfo:
        return CrackInfo(
            success_likelihood=0.1,
            # TODO: actually calculate runtimes
            success_runtime=1e-8,
            failure_runtime=1e-8,
        )

    @staticmethod
    def getTarget() -> str:
        return "xortool"

    def attemptCrack(self, ctext: str) -> List[CrackResult]:
        logging.debug("Trying xortool cipher")
        # TODO handle different charsets
        # TODO allow more config over xortool

        logging.debug(f"{ctext}")

        # https://github.com/Ciphey/xortool/discussions/4
        # for docs on this function
        try:
            result = tool_main.api(str.encode(ctext))
        except:
            logging.debug("Xor failed.")
            return

        result = CrackResult(value=result[1]["Dexored"], key_info=result[0]["keys"])

        return [result]

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "expected": ParamSpec(
                desc="The expected distribution of the plaintext",
                req=False,
                config_ref=["default_dist"],
            ),
            "p_value": ParamSpec(
                desc="The p-value to use for standard frequency analysis",
                req=False,
                default=0.01,
            ),
        }

    @staticmethod
    def score_utility() -> float:
        return 1.5

    def __init__(self, config: Config):
        super().__init__(config)
        self.expected = config.get_resource(self._params()["expected"])
        self.cache = config.cache
        self.p_value = self._params()["p_value"]


================================================
FILE: ciphey/basemods/Decoders/__init__.py
================================================
from . import (
    a1z26,
    atbash,
    base58_bitcoin,
    base58_ripple,
    base62,
    base69,
    base91,
    bases,
    baudot,
    binary,
    braille,
    brainfuck,
    decimal,
    dna,
    dtmf,
    galactic,
    gzip,
    hexadecimal,
    leetspeak,
    morse_code,
    multi_tap,
    octal,
    reverse,
    tap_code,
    unicode,
    url,
    uuencode,
)


================================================
FILE: ciphey/basemods/Decoders/a1z26.py
================================================
import re
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class A1z26(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs A1Z26 decoding
        """
        logging.debug("Attempting A1Z26")
        ctext_converted = []
        ctext_split = re.split(r"[ ,;:\-\n]", ctext)
        delimiters = set(sorted(re.sub(r"[^ ,;:\-\n]", "", ctext)))
        ctext_num = re.sub(r"[,;:\-\s]", "", ctext)
        ctext_decoded = ""
        if ctext_num.isnumeric() is False:
            logging.debug("Failed to decode A1Z26 due to non numeric character(s)")
            return None
        try:
            for i in ctext_split:
                val = int(i)
                if val > 26 or val < 1:
                    logging.debug(
                        f"Failed to decode A1Z26 due to invalid number '{val}'"
                    )
                    return None
                val2 = int(i) + 96
                ctext_converted.append(chr(val2))
            ctext_decoded = "".join(ctext_converted)
            logging.info(
                f"A1Z26 successful, returning '{ctext_decoded}' with delimiter(s) {delimiters}"
            )
            return ctext_decoded
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "a1z26"


================================================
FILE: ciphey/basemods/Decoders/atbash.py
================================================
from typing import Dict, Optional

from ciphey.common import fix_case
from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry


@registry.register
class Atbash(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Takes an encoded string and attempts to decode it according to the Atbash cipher.

        The Atbash cipher is a very simple substitution cipher without a key.
        It operates by replacing every letter in the input by its 'counterpoint'
        in the alphabet. Example: A -> Z, B -> Y, ... , M -> N and vice versa.
        """

        result = ""
        atbash_dict = {self.ALPHABET[i]: self.ALPHABET[::-1][i] for i in range(26)}

        for letter in ctext.lower():
            if letter in atbash_dict.keys():
                # Match every letter of the input to its atbash counterpoint
                result += atbash_dict[letter]
            else:
                # If the current character is not in the defined alphabet,
                # just accept it as-is (useful for numbers, punctuation, etc.)
                result += letter
        return fix_case(result, ctext)

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.1

    def __init__(self, config: Config):
        super().__init__(config)
        self.ALPHABET = config.get_resource(self._params()["dict"], WordList)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The alphabet used for the atbash operation.",
                req=False,
                default="cipheydists::list::englishAlphabet",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "atbash"


================================================
FILE: ciphey/basemods/Decoders/base58_bitcoin.py
================================================
from typing import Dict, Optional

import base58

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base58_bitcoin(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base58 (Bitcoin) decoding
        """
        try:
            return base58.b58decode(ctext).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base58_bitcoin"


================================================
FILE: ciphey/basemods/Decoders/base58_flickr.py
================================================
from typing import Dict, Optional

import base58

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base58_flickr(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base58 (Flickr) decoding
        """
        FLICKR_ALPHABET = b"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
        try:
            return base58.b58decode(ctext, alphabet=FLICKR_ALPHABET).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base58_flickr"


================================================
FILE: ciphey/basemods/Decoders/base58_ripple.py
================================================
from typing import Dict, Optional

import base58

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base58_ripple(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base58 (Ripple) decoding
        """
        try:
            return base58.b58decode(ctext, alphabet=base58.RIPPLE_ALPHABET).decode(
                "utf-8"
            )
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base58_ripple"


================================================
FILE: ciphey/basemods/Decoders/base62.py
================================================
from typing import Dict, Optional

import base62

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base62(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base62 decoding
        """
        try:
            return base62.decodebytes(ctext).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base62"


================================================
FILE: ciphey/basemods/Decoders/base64_url.py
================================================
import base64
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base64_url(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base64 URL decoding
        """
        ctext_padding = ctext + "=" * (4 - len(ctext) % 4)
        try:
            return base64.urlsafe_b64decode(ctext_padding).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base64_url"


================================================
FILE: ciphey/basemods/Decoders/base65536.py
================================================
from typing import Dict, Optional

import base65536

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base65536(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base65536 decoding
        """
        try:
            return base65536.decode(ctext).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base65536"


================================================
FILE: ciphey/basemods/Decoders/base69.py
================================================
# Translated to Python and adapted for Ciphey from the JS original at https://github.com/pshihn/base69


import re
from math import ceil
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry


@registry.register
class Base69(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base69 decoding
        """
        # Remove whitespace
        try:
            ctext = re.sub(r"\s+", "", ctext, flags=re.UNICODE)
            extra_bytes = 0
            clen = len(ctext)

            if ctext[:-1] == "=":
                extra_bytes = int(ctext[clen - 2])

            CHUNK_COUNT = ceil(clen / 16)
            result = [0 for _ in range(CHUNK_COUNT * 7 - extra_bytes)]

            for i in range(CHUNK_COUNT):
                chunk_string = ctext[i * 16 : (i + 1) * 16]
                if extra_bytes and (i == CHUNK_COUNT - 1):
                    insert = self.decode_chunk(chunk_string)
                    for n, elem in enumerate(insert[0 : 7 - extra_bytes]):
                        result[n + i * 7] = elem
                else:
                    insert = self.decode_chunk(chunk_string)
                    for n, elem in enumerate(insert):
                        result[n + i * 7] = elem % 256
            return bytearray(result).decode().strip("\x00")
        except Exception:
            return None

    def decode_chunk(self, s: str):
        padded_bytes = s.endswith("=")

        decoded = [0 for _ in range(8)]
        for i in range(8):
            decoded[i] = (
                0
                if i == 7 and padded_bytes
                else self.chars_to_byte(s[i * 2 : i * 2 + 2])
            )

        result = [0 for _ in range(7)]
        for i in range(7):
            t1 = decoded[i] << (i + 1)
            t2 = decoded[i + 1] >> (7 - i - 1)
            result[i] = t1 | t2
        return result

    def chars_to_byte(self, s: str):
        return (69 * self.CHARS.index(s[1])) + (self.CHARS.index(s[0]))

    @staticmethod
    def priority() -> float:
        # If this becomes lower or equal to the reverse, it breaks.
        # So I'll set it to 0.2 for now since it is very fast anyways.
        return 0.2

    def __init__(self, config: Config):
        super().__init__(config)
        self.CHARS = config.get_resource(self._params()["dict"], WordList)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The charset used for the decoder.",
                req=False,
                default="cipheydists::list::base69",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "base69"


================================================
FILE: ciphey/basemods/Decoders/base91.py
================================================
from typing import Dict, Optional

import base91

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Base91(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Base91 decoding
        """
        try:
            return base91.decode(ctext).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "base91"


================================================
FILE: ciphey/basemods/Decoders/bases.py
================================================
import base64
import types
from typing import Any, Callable, Optional

import logging
from rich.logging import RichHandler
import re

from ciphey.common import id_lambda
from ciphey.iface import Decoder, registry


def _dispatch(self: Any, ctext: str, func: Callable[[str], bytes]) -> Optional[bytes]:
    logging.debug(f"Attempting {self.getTarget()}")

    try:
        # remove all whitespace
        ctext = re.sub(r"\s+", "", ctext, re.UNICODE)
        result = func(ctext)
        logging.info(f"{self.getTarget()} successful, returning {result}")
        return result
    except ValueError:
        logging.debug(f"Failed to decode {self.getTarget()}")
        return None


_bases = {
    "base16": (base64.b16decode, 0.4),
    "base32": (base64.b32decode, 0.01),
    "base64": (base64.b64decode, 0.4),
    "base85": (base64.b85decode, 0.01),
    "ascii85": (base64.a85decode, 0.1),
}


def gen_class(name, decoder, priority, ns):
    ns["_get_func"] = id_lambda(decoder)
    ns["decode"] = lambda self, ctext: _dispatch(self, ctext, self._get_func())
    ns["getParams"] = id_lambda(None)
    ns["getTarget"] = id_lambda(name)
    ns["priority"] = id_lambda(priority)
    ns["__init__"] = lambda self, config: super(type(self), self).__init__(config)


for name, (decoder, priority) in _bases.items():
    t = types.new_class(
        name,
        (Decoder[str],),
        exec_body=lambda x: gen_class(name, decoder, priority, x),
    )

    registry.register(t)


================================================
FILE: ciphey/basemods/Decoders/baudot.py
================================================
import re
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Baudot(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        result = ""
        switch_to_digit_map = 0
        if re.search("^[01]{5}$", ctext.split()[0]):
            for i in ctext.split():
                if i == "11011":
                    switch_to_digit_map = 1
                if i == "11111":
                    switch_to_digit_map = 0
                if switch_to_digit_map == 1:
                    result += self.BAUDOT_DICT["+" + i]
                if switch_to_digit_map == 0:
                    result += self.BAUDOT_DICT[i]
            return result
        else:
            return None

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)
        self.BAUDOT_DICT = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The baudot alphabet dictionary to use",
                req=False,
                default="cipheydists::translate::baudot",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "baudot"


================================================
FILE: ciphey/basemods/Decoders/binary.py
================================================
import re
from typing import Dict, List, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Binary(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        try:
            ctext = re.sub(r"[^\S \n]", " ", ctext, flags=re.UNICODE)
            ctext = ctext.replace("\n", " ")

            existing_split = self.try_split(ctext.split(" "))
            if existing_split is not None:
                return existing_split

            # Now we try our own grouping

            # Remove final bit of whitespace
            ctext = ctext.replace(" ", "")
            # Split into bytes, and test
            return self.try_split([ctext[i : i + 8] for i in range(0, len(ctext), 8)])
        # Catch bad octal chars
        except ValueError:
            return None

    def try_split(self, split_text: List[str]):
        ret = []

        for i in split_text:
            if len(i) == 0:
                continue
            val = int(i, 2)
            if val > 255 or val < 0:
                return None
            ret.append(val)

        if len(ret) != 0:
            ret = bytes(ret)
            logging.info(f"binary successful, returning {ret.__repr__()}")
            return ret

    @staticmethod
    def priority() -> float:
        return 0.3

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "binary"


================================================
FILE: ciphey/basemods/Decoders/braille.py
================================================
import re
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
import logging
from rich.logging import RichHandler


@registry.register
class Braille(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Braille decoding
        """
        logging.debug("Attempting Braille")
        ctext_decoded = ""
        braille_matches = 0
        for symbol in self.BRAILLE_DICT_INV.values():
            if symbol in ctext:
                braille_matches += 1
            else:
                continue
        if braille_matches == 0:
            logging.debug("Failed to decode Braille due to invalid characters")
            return None

        for pattern, value in self.BRAILLE_DICT.items():
            ctext = re.sub(pattern, value, ctext)

        wordArr = []
        for word in ctext.split(" "):
            # If two commas are in front of a word, uppercase the word and remove the comma
            if word[:2].find(",,") != -1:
                wordArr.append(word.replace(",,", "").upper())
            else:
                wordArr.append(word)

        result = []
        for word in wordArr:
            # If one comma is in front of a word, capitalize the word and remove the comma
            if word[0].find(",") != -1:
                result.append(word.replace(",", "").capitalize())
            else:
                result.append(word)
        ctext_decoded = " ".join(result)
        logging.info(f"Braille successful, returning '{ctext_decoded}'")
        return ctext_decoded

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)
        self.BRAILLE_DICT = config.get_resource(self._params()["dict"], Translation)
        self.BRAILLE_DICT_INV = {v: k for k, v in self.BRAILLE_DICT.items()}

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The Braille dictionary to use",
                req=False,
                default="cipheydists::translate::braille",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "braille"


================================================
FILE: ciphey/basemods/Decoders/brainfuck.py
================================================
import re
import time
from typing import Dict, Optional, Tuple

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry


@registry.register
class Brainfuck(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Takes a ciphertext and treats it as a Brainfuck program,
        interpreting it and saving the output as a string to return.

        Brainfuck is a very simple, Turing-complete esoteric language.
        Below is a simplified interpreter that attempts to check whether a
        given ciphertext is a brainfuck program that would output a string.

        A program that can be "decoded" like this is one that:
            * Does not require user input ("," instruction)
            * Includes at least one putchar instruction (".")
            * Does not contain anything but the main 7 instructions,
                (excluding ",") and whitespace

        Details:
            * This implementation wraps the memory pointer for ">" and "<"
            * It is time-limited to 60 seconds, to prevent hangups
            * The program starts with 100 memory cells, chosen arbitrarily
        """

        logging.debug("Attempting brainfuck")

        result = ""
        memory = [0] * 100
        codeptr, memptr = 0, 0  # Instruction pointer and stack pointer
        timelimit = 60  # The timeout in seconds

        bracemap, isbf = self.bracemap_and_check(ctext)

        # If it doesn't appear to be valid brainfuck code
        if not isbf:
            logging.debug("Failed to interpret brainfuck due to invalid characters")
            return None

        # Get start time
        start = time.time()

        while codeptr < len(ctext):

            current = time.time()

            # Return none if we've been running for over a minute
            if current - start > timelimit:
                logging.debug("Failed to interpret brainfuck due to timing out")
                return None

            cmd = ctext[codeptr]

            if cmd == "+":
                if memory[memptr] < 255:
                    memory[memptr] = memory[memptr] + 1
                else:
                    memory[memptr] = 0

            elif cmd == "-":
                if memory[memptr] > 0:
                    memory[memptr] = memory[memptr] - 1
                else:
                    memory[memptr] = 255

            elif cmd == ">":
                if memptr == len(memory) - 1:
                    memory.append(0)
                memptr += 1

            elif cmd == "<":
                if memptr == 0:
                    memptr = len(memory) - 1
                else:
                    memptr -= 1

            # If we're at the beginning of the loop and the memory is 0, exit the loop
            elif cmd == "[" and memory[memptr] == 0:
                codeptr = bracemap[codeptr]

            # If we're at the end of the loop and the memory is >0, jmp to the beginning of the loop
            elif cmd == "]" and memory[memptr]:
                codeptr = bracemap[codeptr]

            # Store the output as a string instead of printing it out
            elif cmd == ".":
                result += chr(memory[memptr])

            codeptr += 1

        logging.info(f"Brainfuck successful, returning '{result}'")
        return result

    def bracemap_and_check(self, program: str) -> Tuple[Optional[Dict], bool]:
        """
        Create a bracemap of brackets in the program, to compute jmps.
        Maps open -> close brackets as well as close -> open brackets.

        Also returns True if the program is valid Brainfuck code. If False, we
        won't even try to run it.
        """

        open_stack = []
        bracemap = dict()
        legal_instructions = {"+", "-", ">", "<", "[", "]", "."}
        legal_count = 0

        # If the program actually outputs anything (contains ".")
        prints = False

        for idx, instruction in enumerate(program):
            # If instruction is brainfuck (without input) or whitespace, it counts
            if instruction in legal_instructions or re.match(r"\s", instruction):
                legal_count += 1

            if not prints and instruction == ".":
                # If there are no "." instructions then this program will not output anything
                prints = True

            elif instruction == "[":
                open_stack.append(idx)

            elif instruction == "]":
                try:
                    opbracket = open_stack.pop()
                    bracemap[opbracket] = idx
                    bracemap[idx] = opbracket
                except IndexError:
                    # Mismatched braces, not a valid program
                    # Closing braces > opening braces
                    return (None, False)

        # 1. All characters are instructions or whitespace
        # 2. There are no extra open braces
        # 3. There is at least one character to be "printed"
        # (result is >=1 in length)
        is_brainfuck = legal_count == len(program) and len(open_stack) == 0 and prints

        return bracemap, is_brainfuck

    @staticmethod
    def priority() -> float:
        # Not uncommon, but not very common either. It's also slow.
        return 0.08

    def __init__(self, config: Config):
        super().__init__(config)
        self.ALPHABET = config.get_resource(self._params()["dict"], WordList)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="Brainfuck alphabet (default English)",
                req=False,
                default="cipheydists::list::englishAlphabet",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "brainfuck"


================================================
FILE: ciphey/basemods/Decoders/decimal.py
================================================
import re
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Decimal(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Decimal decoding
        """
        logging.debug("Attempting decimal")
        ctext_converted = []
        ctext_split = re.split(r"[ ,;:\-\n]", ctext)
        delimiters = set(sorted(re.sub(r"[^ ,;:\-\n]", "", ctext)))
        ctext_num = re.sub(r"[,;:\-\s]", "", ctext)
        ctext_decoded = ""
        if ctext_num.isnumeric() is False:
            logging.debug("Failed to decode decimal due to non numeric character(s)")
            return None
        try:
            for i in ctext_split:
                val = int(i)
                if val > 255 or val < 0:
                    logging.debug(
                        f"Failed to decode decimal due to invalid number '{val}'"
                    )
                    return None
                ctext_converted.append(chr(val))
            ctext_decoded = "".join(ctext_converted)
            logging.info(
                f"Decimal successful, returning '{ctext_decoded}' with delimiter(s) {delimiters}"
            )
            return ctext_decoded
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "decimal"


================================================
FILE: ciphey/basemods/Decoders/dna.py
================================================
import re
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Dna(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs DNA decoding
        """
        logging.debug("Attempting DNA decoder")
        ctext_decoded = ""
        ctext = re.sub(r"[,;:\-\s]", "", ctext)
        ctext = " ".join(ctext[i : i + 3] for i in range(0, len(ctext), 3))
        ctext_split = ctext.split(" ")
        dna_keys = self.DNA_DICT.keys()

        for i in ctext_split:
            if i in dna_keys:
                ctext_decoded += self.DNA_DICT[i]
            else:
                return None
        logging.info(f"DNA successful, returning '{ctext_decoded}'")
        return ctext_decoded

    @staticmethod
    def priority() -> float:
        return 0.2

    def __init__(self, config: Config):
        super().__init__(config)
        self.DNA_DICT = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The DNA alphabet dictionary to use",
                req=False,
                default="cipheydists::translate::dna",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "dna"


================================================
FILE: ciphey/basemods/Decoders/dtmf.py
================================================
import re
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Dtmf(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs DTMF decoding
        """
        logging.debug("Attempting DTMF decoder")
        ctext_decoded = ""
        ctext = re.sub(r"[,;:\-\/\s]", "", ctext)
        ctext = " ".join(ctext[i : i + 7] for i in range(0, len(ctext), 7))
        ctext_split = ctext.split(" ")
        dtmf_keys = self.DTMF_DICT.keys()

        for i in ctext_split:
            if i in dtmf_keys:
                ctext_decoded += self.DTMF_DICT[i]
            else:
                return None
        logging.info(f"DTMF successful, returning '{ctext_decoded}'")
        return ctext_decoded

    @staticmethod
    def priority() -> float:
        return 0.2

    def __init__(self, config: Config):
        super().__init__(config)
        self.DTMF_DICT = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The DTMF alphabet dictionary to use",
                req=False,
                default="cipheydists::translate::dtmf",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "dtmf"


================================================
FILE: ciphey/basemods/Decoders/galactic.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Galactic(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Takes a string written in the 'Standard Galactic Alphabet'
        (aka Minecraft Enchanting Table Symbols) and translates it to ASCII text.
        """
        logging.debug("Attempting Standard Galactic Alphabet decoder")

        # To avoid complications, only move forward with the decoding if we can
        # reasonably assume that the input string is written in the galactic alphabet
        galactic_matches = 0
        for symbol in self.GALACTIC_DICT.keys():
            # These symbols are assumed to be frequent enough in regular
            # text to be skipped when counting the matches. All others are counted.
            if symbol in ctext and symbol not in ["!", "|"]:
                galactic_matches += 1
            else:
                continue
        if galactic_matches == 0:
            logging.debug(
                "No matching galactic alphabet letters found. Skipping galactic decoder"
            )
            return None
        logging.debug(f"{galactic_matches} galactic alphabet letters found. ")

        result = ""
        # Take out the problematic characters consisting of multiple symbols
        ctext = (
            ctext.replace("||", "|")
            .replace("/", "")
            .replace("¡", "")
            .replace(" ̣ ", "")
            .replace("̇", "x")
        )
        logging.debug(f"Modified string is {ctext}")

        for letter in ctext:
            if letter in self.GALACTIC_DICT.keys():
                # Match every letter of the input to its galactic counterpoint
                result += self.GALACTIC_DICT[letter]
            else:
                # If the current character is not in the defined alphabet,
                # just accept it as-is (useful for numbers, punctuation, etc.)
                result += letter
        # Remove the trailing space (appearing as a leading space)
        # from the x that results from the diacritic replacement
        result = result.replace("x ", "x")
        logging.debug(f"Decoded string is {result}")
        return result

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.01

    def __init__(self, config: Config):
        super().__init__(config)
        self.GALACTIC_DICT = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The galactic alphabet dictionary to use",
                req=False,
                default="cipheydists::translate::galactic",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "galactic"


================================================
FILE: ciphey/basemods/Decoders/gzip.py
================================================
import zlib
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Gzip(Decoder[bytes]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Gzip decoding
        """
        try:
            return zlib.decompress(ctext, 16 + zlib.MAX_WBITS).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "gzip"


================================================
FILE: ciphey/basemods/Decoders/hexadecimal.py
================================================
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Hexadecimal(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Hexadecimal decoding
        """
        ctext_decoded = ""
        try:
            ctext_decoded = bytearray.fromhex(ctext).decode("utf-8")
            return ctext_decoded
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        return 0.015

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "hexadecimal"


================================================
FILE: ciphey/basemods/Decoders/leetspeak.py
================================================
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Leetspeak(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        for src, dst in self.translate.items():
            ctext = ctext.replace(src, dst)
        return ctext

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)
        self.translate = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The leetspeak dictionary to use",
                req=False,
                default="cipheydists::translate::leet",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "leetspeak"


================================================
FILE: ciphey/basemods/Decoders/letters.archive
================================================
"""
Not yet implemented.
"""
class letters:

    """Deals with Nato Strings / first letter of every word"""

    def __init__(self):
        None

    def __name__(self):
        return "Letters"

    def decrypt(self, text: str) -> dict:
        return text

    def first_letter_every_word(self, text):
        """
        This should be supplied a string like "hello my name is"
        """

        text = text.split(".")

        new_text = []
        for sentence in text:
            for word in sentence.split(" "):
                new_text.append(word[0])
            # Applies a space after every sentence
            # which might be every word
            new_text.append(" ")


================================================
FILE: ciphey/basemods/Decoders/morse_code.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Morse_code(Decoder[str]):
    # A priority list for char/word boundaries
    BOUNDARIES = {" ": 1, "/": 2, "\n": 3}
    PURGE = {ord(c): None for c in BOUNDARIES.keys()}
    MAX_PRIORITY = 3
    ALLOWED = {".", "-", " ", "/", "\n"}
    MORSE_CODE_DICT: Dict[str, str]
    MORSE_CODE_DICT_INV: Dict[str, str]

    def decode(self, ctext: T) -> Optional[U]:
        logging.debug("Attempting Morse code decoder")

        char_boundary = word_boundary = None

        char_boundary = word_boundary = None
        char_priority = word_priority = 0
        # Custom loop allows early break
        for i in ctext:
            i_priority = self.BOUNDARIES.get(i)
            if i_priority is None:
                if i in self.ALLOWED:
                    continue
                logging.debug(f"Non-morse char '{i}' found")
                return None

            if i_priority <= char_priority or i == char_boundary or i == word_boundary:
                continue
            # Default to having a char boundary over a word boundary
            if (
                i_priority > word_priority
                and word_boundary is None
                and char_boundary is not None
            ):
                word_priority = i_priority
                word_boundary = i
                continue
            char_priority = i_priority
            char_boundary = i

        logging.debug(
            f"Char boundary is unicode {ord(char_boundary)}, and word boundary is unicode {ord(word_boundary) if word_boundary is not None else None}"
        )

        result = ""

        for word in ctext.split(word_boundary) if word_boundary else [ctext]:
            logging.debug(f"Attempting to decode word {word}")
            for char in word.split(char_boundary):
                char = char.translate(self.PURGE)
                if len(char) == 0:
                    continue
                try:
                    m = self.MORSE_CODE_DICT_INV[char]
                except KeyError:
                    logging.debug(f"Invalid codeword '{char}' found")
                    return None
                result = result + m
            # after every word add a space
            result = result + " "
        if len(result) == 0:
            logging.debug("Morse code failed to match")
            return None
        # Remove trailing space
        result = result[:-1]
        logging.info(f"Morse code successful, returning {result}")
        return result.strip().upper()

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)
        self.MORSE_CODE_DICT = config.get_resource(self._params()["dict"], Translation)
        self.MORSE_CODE_DICT_INV = {v: k for k, v in self.MORSE_CODE_DICT.items()}

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The morse code dictionary to use",
                req=False,
                default="cipheydists::translate::morse",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "morse_code"


================================================
FILE: ciphey/basemods/Decoders/multi_tap.py
================================================
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Multi_tap(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        result = ""
        for x in ctext.split():
            if x == self.SPACE_DIGIT:  # Check if it's a space
                result += " "
            elif not Multi_tap.valid_code_part(x):
                return None
            else:
                result += self.decode_num_to_char(x)

        return result

    @staticmethod
    def valid_code_part(code: str) -> bool:
        if not code.isdigit():
            return False

        # if not all the digits are the same
        if not Multi_tap.is_all_dup(code):
            return False

        if int(code[0]) not in range(2, 10):
            return False

        if len(code) > 4:
            return False

        return True

    @staticmethod
    def decode_num_to_char(number: str) -> str:
        index = Multi_tap.calculate_index(number)
        return Multi_tap.number_index_to_char(index)

    @staticmethod
    def is_all_dup(code):
        return len(set(code)) == 1

    @staticmethod
    def calculate_index(number: str) -> int:
        first_number_as_int = int(number[0])

        number_index = Multi_tap.get_index_from_first_digit(first_number_as_int)

        # Add to index the number of the char : "22" -> index += 1
        num_rest_numbers = len(number) - 1
        number_index += num_rest_numbers

        return number_index

    @staticmethod
    def number_index_to_char(index_number: int) -> str:
        start_ascii_value = ord("A")
        return chr(start_ascii_value + index_number)

    @staticmethod
    def get_index_from_first_digit(first_digit: int) -> int:
        number_index = 0
        if first_digit >= 8:  # s have 4 chars
            number_index += 1

        first_digit -= 2  # start in 200

        number_index += first_digit * 3  # jump 3 every time

        return number_index

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)
        self.SPACE_DIGIT = "0"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "multi_tap"


================================================
FILE: ciphey/basemods/Decoders/octal.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Octal(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Octal decoding
        """
        str_converted = []
        octal_seq = ctext.split(" ")
        if len(octal_seq) == 1:
            # Concatted octal must be formed of octal triplets
            if len(ctext) % 3 != 0:
                return None
            octal_seq = [ctext[i : i + 3] for i in range(0, len(ctext), 3)]
            logging.debug(f"Trying chunked octal {octal_seq}")
        try:
            for octal_char in octal_seq:
                if len(octal_char) > 3:
                    logging.debug("Octal subseq too long")
                    return None
                n = int(octal_char, 8)
                if (
                    n < 0
                ):  # n cannot be greater than 255, as we checked that with the earlier length check
                    logging.debug(f"Non octal char {octal_char}")
                    return None
                str_converted.append(n)

            return bytes(str_converted)
        # Catch bad octal chars
        except ValueError:
            return None

    @staticmethod
    def priority() -> float:
        return 0.025

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "octal"


================================================
FILE: ciphey/basemods/Decoders/reverse.py
================================================
from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Reverse(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        return ctext[::-1]

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "reverse"


================================================
FILE: ciphey/basemods/Decoders/tap_code.py
================================================
# by https://github.com/RustyDucky and https://github.com/lukasgabriel

from typing import Dict, Optional

from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry


@registry.register
class Tap_code(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Tap code decoding
        """
        try:
            result = ""
            combinations = ctext.split(" ")
            for fragment in combinations:
                result += self.TABLE.get(fragment)
            return result
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        return 0.06

    def __init__(self, config: Config):
        super().__init__(config)
        self.TABLE = config.get_resource(self._params()["dict"], Translation)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {
            "dict": ParamSpec(
                desc="The table of letters used for the tap code interpretation.",
                req=False,
                default="cipheydists::translate::tap_code",
            )
        }

    @staticmethod
    def getTarget() -> str:
        return "tap_code"


================================================
FILE: ciphey/basemods/Decoders/unicode.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Utf8(Decoder[bytes]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs UTF-8 decoding
        """
        logging.debug("Attempting UTF-8 decoder")
        result = ""
        try:
            result = ctext.decode("utf-8")
            if result != ctext:
                logging.info(f"UTF-8 successful, returning '{result}'")
                return result
            else:
                return None
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        return 0.9

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "utf8"


================================================
FILE: ciphey/basemods/Decoders/url.py
================================================
from typing import Dict, Optional
from urllib.parse import unquote_plus

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Url(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs URL decoding
        """
        logging.debug("Attempting URL")
        result = ""
        try:
            result = unquote_plus(ctext, errors="strict")
            if result != ctext:
                logging.info(f"URL successful, returning '{result}'")
                return result
            else:
                return None
        except Exception:
            logging.debug("Failed to decode URL")
            return None

    @staticmethod
    def priority() -> float:
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "url"


================================================
FILE: ciphey/basemods/Decoders/uuencode.py
================================================
from binascii import a2b_uu
from codecs import decode
from typing import Dict, Optional

import logging
from rich.logging import RichHandler

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Uuencode(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        UUEncode (Unix to Unix Encoding) is a symmetric encryption
        based on conversion of binary data (split into 6-bit blocks) into ASCII characters.

        This function decodes the input string 'ctext' if it has been encoded using 'uuencoder'
        It will return None otherwise
        """
        logging.debug("Attempting UUencode")
        result = ""
        try:
            # UUencoded messages may begin with prefix "begin" and end with suffix "end"
            # In that case, we use the codecs module in Python
            ctext_strip = ctext.strip()
            if ctext_strip.startswith("begin") and ctext_strip.endswith("end"):
                result = decode(bytes(ctext, "utf-8"), "uu").decode()
            else:
                # If there isn't a "being" prefix and "end" suffix, we use the binascii module instead
                # It is possible that the ctext has multiple lines, so convert each line and append
                ctext_split = list(filter(None, ctext.splitlines()))
                for _, value in enumerate(ctext_split):
                    result += a2b_uu(value).decode("utf-8")
            logging.info(f"UUencode successful, returning '{result}'")
            return result
        except Exception:
            logging.debug("Failed to decode UUencode")
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "uuencode"


================================================
FILE: ciphey/basemods/Decoders/z85.py
================================================
from typing import Dict, Optional

import logging
from rich.logging import RichHandler
from zmq.utils import z85

from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry


@registry.register
class Z85(Decoder[str]):
    def decode(self, ctext: T) -> Optional[U]:
        """
        Performs Z85 decoding
        """
        ctext_len = len(ctext)
        if ctext_len % 5:
            logging.debug(
                f"Failed to decode Z85 because length must be a multiple of 5, not '{ctext_len}'"
            )
            return None
        try:
            return z85.decode(ctext).decode("utf-8")
        except Exception:
            return None

    @staticmethod
    def priority() -> float:
        # Not expected to show up often, but also very fast to check.
        return 0.05

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None

    @staticmethod
    def getTarget() -> str:
        return "z85"


================================================
FILE: ciphey/basemods/Resources/__init__.py
================================================
from . import cipheydists, files


================================================
FILE: ciphey/basemods/Resources/cipheydists.py
================================================
from functools import lru_cache
from typing import Any, Dict, Optional, Set

import cipheydists
import logging

from ciphey.iface import (
    Config,
    Distribution,
    ParamSpec,
    ResourceLoader,
    Translation,
    WordList,
    registry,
)


@registry.register_multi(WordList, Distribution, Translation)
class CipheyDists(ResourceLoader):
    # _wordlists: Set[str] = frozenset({"english", "english1000", "englishStopWords"})
    # _brandons: Set[str] = frozenset({"english"})
    # _dists: Set[str] = frozenset({"twist"})
    # _translates: Set[str] = frozenset({"morse"})
    _getters = {
        "list": cipheydists.get_list,
        "dist": cipheydists.get_dist,
        "brandon": cipheydists.get_brandon,
        "translate": cipheydists.get_translate,
    }

    def whatResources(self) -> Optional[Set[str]]:
        pass

    @lru_cache()
    def getResource(self, name: str) -> Any:
        logging.debug(f"Loading cipheydists resource {name}")
        prefix, name = name.split("::", 1)
        return self._getters[prefix](name)

    def __init__(self, config: Config):
        super().__init__(config)

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return None


================================================
FILE: ciphey/basemods/Resources/files.py
================================================
import csv
import json
from functools import lru_cache
from typing import Dict, Generic, Optional, Set

from ciphey.iface import (
    Config,
    Distribution,
    ParamSpec,
    ResourceLoader,
    T,
    WordList,
    registry,
)


# We can use a generic resource loader here, as we can instantiate it later
@registry.register_multi(WordList, Distribution)
class Json(ResourceLoader):
    def whatResources(self) -> T:
        return self._names

    @lru_cache()
    def getResource(self, name: str) -> T:
        prefix, name = name.split("::", 1)
        return {"wordlist": (lambda js: {js}), "dist": (lambda js: js)}[prefix](
            json.load(open(self._paths[int(name) - 1]))
        )

    @staticmethod
    def getName() -> str:
        return "json"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {"path": ParamSpec(req=True, desc="The path to a JSON file", list=True)}

    def __init__(self, config: Config):
        super().__init__(config)
        self._paths = self._params()["path"]
        self._names = set(range(1, len(self._paths)))


# We can use a generic resource loader here, as we can instantiate it later
@registry.register_multi(WordList, Distribution)
class Csv(Generic[T], ResourceLoader[T]):
    def whatResources(self) -> Set[str]:
        return self._names

    @lru_cache()
    def getResource(self, name: str) -> T:
        prefix, name = name.split("::", 1)
        return {
            "wordlist": (lambda reader: {i[0] for i in reader}),
            "dist": (lambda reader: {i[0]: float(i[1]) for i in reader}),
        }[prefix](csv.reader(open(self._paths[int(name) - 1])))

    @staticmethod
    def getName() -> str:
        return "csv"

    @staticmethod
    def getParams() -> Optional[Dict[str, ParamSpec]]:
        return {"path": ParamSpec(req=True, desc="The path to a CSV file", list=True)}

    def __init__(self, config: Config):
        super().__init__(config)
        self._paths = self._params()["path"]
        self._names = set(range(1, len(self._paths)))


================================================
FILE: ciphey/basemods/Searchers/__init__.py
================================================
from . import ausearch


================================================
FILE: ciphey/basemods/Searchers/astar.py
================================================
import cipheycore


class Node:
    """
    A node has a value associated with it
    Calculated from the heuristic
    """

    def __init__(
        self,
        config,
        h: float = None,
        edges: (any, float) = None,
        ctext: str = None,
    ):
        self.weight = h
        # Edges is a list of other nodes it can connect to
        self.edges = edges
        self.ctext = ctext
        self.h = h
        self.path = []
        self.information_content = config.cache.get_or_update(
            self.text,
            "cipheycore::info_content",
            lambda: cipheycore.info_content(self.ctext),
        )

    def __le__(self, node2):
        # if self is less than other
        return self.x <= node2.x

    def __lt__(self, node2):
        return self.x < node2.x

    def append_edge(self, edge):
        self.edges.append(edge)

    def get_edges(self):
        return self.edges


class Graph:
    # example of adjacency list (or rather map)
    # adjacency_list = {
    # 'A': [('B', 1), ('C', 3), ('D', 7)],
    # 'B': [('D', 5)],
    # 'C': [('D', 12)]
    # }

    def __init__(self, adjacency_list):
        """
        adjacency list: basically the graph
        """
        self.adjacency_list = adjacency_list
        self.original_input = cipheycore.info_content(input)

    def get_neighbors(self, v):
        try:
            return self.adjacency_list[v]
        except KeyError:
            # If we have exhausted the adjacency list
            return []

    # heuristic function with equal values for all nodes
    def heuristic(self, n: Node):
        return n.info_content / self.original_input

    def a_star_algorithm(self, start_node: Node, stop_node: Node):
        # TODO store the graph as an attribute
        # open_list is a list of nodes which have been visited, but who's neighbors
        # haven't all been inspected, starts off with the start node
        # closed_list is a list of nodes which have been visited
        # and who's neighbors have been inspected
        open_list = set([start_node])
        closed_list = set([])

        # g contains current distances from start_node to all other nodes
        # the default value (if it's not found in the map) is +infinity
        g = {}

        g[start_node] = 0

        # parents contains an adjacency map of all nodes
        parents = {}
        parents[start_node] = start_node

        while len(open_list) > 0:
            print(f"The open list is {open_list}")
            n = None

            # find a node with the lowest value of f() - evaluation function
            for v in open_list:
                # TODO if v == decoder, run the decoder
                print(f"The for loop node v is {v}")
                if n is None or g[v] + self.h(v) < g[n] + self.h(n):
                    n = v
                    print(f"The value of n is {n}")

            if n is None:
                print("Path does not exist!")
                return None

            # if the current node is the stop_node
            # then we begin reconstructin the path from it to the start_node
            # NOTE Uncomment this for an exit condition
            # TODO Make it exit if decrypter returns True
            # TODO We need to append the decryption methods to each node
            # So when we reconstruct the path we can reconstruct the decryptions
            # used
            if n == stop_node:
                print("n is the stop node, we are stopping!")
                reconst_path = []

                while parents[n] != n:
                    reconst_path.append(n)
                    n = parents[n]

                reconst_path.append(start_node)

                reconst_path.reverse()

                print("Path found: {}".format(reconst_path))
                return reconst_path

            print(n)
            for (m, weight) in self.get_neighbors(n):
                print(f"And the iteration is ({m}, {weight})")
                # if the current node isn't in both open_list and closed_list
                # add it to open_list and note n as it's parent
                if m not in open_list and m not in closed_list:
                    open_list.add(m)
                    parents[m] = n
                    g[m] = g[n] + weight

                # otherwise, check if it's quicker to first visit n, then m
                # and if it is, update parent data and g data
                # and if the node was in the closed_list, move it to open_list
                else:
                    if g[m] > g[n] + weight:
                        g[m] = g[n] + weight
                        parents[m] = n

                        if m in closed_list:
                            closed_list.remove(m)
                            open_list.add(m)

            # remove n from the open_list, and add it to closed_list
            # because all of his neighbors were inspected
            # open_list.remove(node)
            # closed_list.add(node)

            open_list.remove(n)
            closed_list.add(n)
            print("\n")

        print("Path does not exist!")
        return None


adjacency_list = {
    "A": [("B", 1), ("C", 3), ("D", 7)],
    "B": [("D", 5)],
    "C": [("D", 12)],
}
A = Node(1)
B = Node(7)
C = Node(9)
D = Node(16)

A.edges = [(B, 1), (C, 3), (D, 7)]
B.edges = [(D, 5)]
C.edges = [(D, 12)]

# TODO use a dictionary comprehension to make this
adjacency_list = {
    A: A.edges,
    B: B.edges,
    C: C.edges,
}
graph1 = Graph(adjacency_list)
graph1.a_star_algorithm(A, D)

"""
Maybe after it
"""


================================================
FILE: ciphey/basemods/Searchers/atar.md
================================================
function reconstruct_path(cameFrom, current)
    total_path := {current}
    while current in cameFrom.Keys:
        current := cameFrom[current]
        total_path.prepend(current)
    return total_path

// A* finds a path from start to goal.
// h is the heuristic function. h(n) estimates the cost to reach goal from node n.
function A_Star(graph, start, h)
    // The set of discovered nodes that may need to be (re-)expanded.
    // Initially, only the start node is known.
    // This is usually implemented as a min-heap or priority queue rather than a hash-set.
    openSet := {start}

    // For node n, cameFrom[n] is the node immediately preceding it on the cheapest path from start
    // to n currently known.
    cameFrom := an empty map

    // For node n, gScore[n] is the cost of the cheapest path from start to n currently known.
    gScore := map with default value of Infinity
    gScore[start] := 0

    // For node n, fScore[n] := gScore[n] + h(n). fScore[n] represents our current best guess as to
    // how short a path from start to finish can be if it goes through n.
    fScore := map with default value of Infinity
    fScore[start] := h(start)
    
    // the exit condition is set to True when LC returns True
    exit_condition = False

    while not exit_condition
        // This operation can occur in O(1) time if openSet is a min-heap or a priority queue
        current := the node in openSet having the lowest fScore[] value
        if current = goal
            return reconstruct_path(cameFrom, current)

        openSet.Remove(current)
        for each neighbor of current
		decodings = neighbor.decoders()
		
	
	
            // d(current,neighbor) is the weight of the edge from current to neighbor
            // tentative_gScore is the distance from start to the neighbor through current
            tentative_gScore := gScore[current] + d(current, neighbor)
            if tentative_gScore < gScore[neighbor]
                // This path to neighbor is better than any previous one. Record it!
                cameFrom[neighbor] := current
                gScore[neighbor] := tentative_gScore
                fScore[neighbor] := gScore[neighbor] + h(neighbor)
                if neighbor not in openSet
                    openSet.add(neighbor)
		
		    # run the cracker on the object
			    crack(node.ctext)
		    if crack:
			    # if cracker returns true, reconstruct path and exiti
			    exit_condition = True
			    reconstruct(start, node)
		    else:
			    # else add the new children of the cracker to openSet
			    openSet.append(node: crack)
		
		
		

    // Open set is empty but goal was never reached
    return failure
    

function reconstruct_path(cameFrom, current)
    total_path := {current}
    while current in cameFrom.Keys:
        current := cameFrom[current]
        total_path.prepend(current)
    return total_path

// A* finds a path from start to goal.
// h is the heuristic function. h(n) estimates the cost to reach goal from node n.
function A_Star(graph, start, h)
    // The set of discovered nodes that may need to be (re-)expanded.
    // Initially, only the start node is known.
    // This is usually implemented as a min-heap or priority queue rather than a hash-set.
    openSet := {start}

    // For node n, cameFrom[n] is the node immediately preceding it on the cheapest path from start
    // to n currently known.
    cameFrom := an empty map

    // For node n, gScore[n] is the cost of the cheapest path from start to n currently known.
    gScore := map with default value of Infinity
    gScore[start] := 0

    // For node n, fScore[n] := gScore[n] + h(n). fScore[n] represents our current best guess as to
    // how short a path from start to finish can be if it goes through n.
    fScore := map with default value of Infinity
    fScore[start] := h(start)
    
    // the exit condition is set to True when LC returns True
    exit_condition = False

    while not exit_condition
        // This operation can occur in O(1) time if openSet is a min-heap or a priority queue
        current := the node in openSet having the lowest fScore[] value
        if current = goal
            return reconstruct_path(cameFrom, current)

        openSet.Remove(current)
        for each neighbor of current
		decodings = neighbor.decoders()
		
	
	
            // d(current,neighbor) is the weight of the edge from current to neighbor
            // tentative_gScore is the distance from start to the neighbor through current
            tentative_gScore := gScore[current] + d(current, neighbor)
            if tentative_gScore < gScore[neighbor]
                // This path to neighbor is better than any previous one. Record it!
                cameFrom[neighbor] := current
                gScore[neighbor] := tentative_gScore
                fScore[neighbor] := gScore[neighbor] + h(neighbor)
                if neighbor not in openSet
                    openSet.add(neighbor)
		
		    # run the cracker on the object
			    crack(node.ctext)
		    if crack:
			    # if cracker returns true, reconstruct path and exiti
			    exit_condition = True
			    reconstruct(start, node)
		    else:
			    # else add the new children of the cracker to openSet
			    openSet.append(node: crack)
		
		
		

    // Open set is empty but goal was never reached
    
function calculate_new_children(node):

    
class Node:
    """
    A node has a value associated with it
    Calculated from the heuristic
    """

    def __init__(self, h: float = None, edges: (any, float) = None, ctext: str = None):
        self.weight = h
        # Edges is a list of other nodes it can connect to
        self.edges = edges
        self.ctext = ctext
        self.h = h
        self.path = []
        self.information_content = config.cache.get_or_update(
            self.ctext,
            "cipheycore::info_content",
            lambda: cipheycore.info_content(self.ctext),
        )

    def __le__(self, node2):
        # if self is less than other
        return self.x <= node2.x

    def __lt__(self, node2):
        return self.x < node2.x

    def append_edge(self, edge):
        self.edges.append(edge)

    def get_edges(self):
        return self.edges


================================================
FILE: ciphey/basemods/Searchers/ausearch.py
================================================
import bisect
import distutils
import math
from copy import copy
from dataclasses import dataclass
from functools import lru_cache
from typing import Any, Dict, Generic, List, Optional, TypeVar, Union

import logging
from rich.logging import RichHandler

from ciphey.iface import (
    Checker,
    Config,
    Cracker,
    CrackInfo,
    CrackResult,
    Decoder,
    ParamSpec,
    Searcher,
    SearchLevel,
    SearchResult,
    T,
    registry,
)

"""
We are using a tree structure here, because that makes searching and tracing back easier
As such, when we encounter another possible parent, we remove that edge
"""


class DuplicateNode(Exception):
    pass


@dataclass
class AuSearchSuccessful(Exception):
    target: "Node"
    info: str


@dataclass
class Node:
    # The root has no parent edge
    level: SearchLevel
    parent: Optional["Edge"] = None
    depth: int = 0

    @staticmethod
    def decoding(
        config: Config, route: Union[Cracker, Decoder], result: Any, source: "Node"
    ) -> "Node":
        if not config.cache.mark_ctext(result):
            raise DuplicateNode()

        checker: Checker = config.objs["checker"]
        ret = Node(
            parent=None,
            level=SearchLevel(
                name=type(route).__name__.lower(), result=CrackResult(value=r
Download .txt
gitextract_ft4u3o1q/

├── .all-contributorsrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   ├── feature_request.md
│   │   └── maintenance_suggestion.md
│   ├── config.yml
│   ├── dependabot.yml
│   ├── lock.yml
│   ├── release-drafter.yml
│   └── workflows/
│       ├── coverage.yml
│       ├── release.yml
│       ├── releasetestpypi.yml
│       ├── terminaltest.yml
│       └── tests2.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Pictures_for_README/
│   └── .gitattributes
├── README.md
├── ciphey/
│   ├── __init__.py
│   ├── __main__.py
│   ├── basemods/
│   │   ├── Checkers/
│   │   │   ├── __init__.py
│   │   │   ├── any.py
│   │   │   ├── brandon.py
│   │   │   ├── entropy.py
│   │   │   ├── ezcheck.py
│   │   │   ├── format.py
│   │   │   ├── gtest.py
│   │   │   ├── human.py
│   │   │   ├── quadgrams.py
│   │   │   ├── quorum.py
│   │   │   ├── regex.py
│   │   │   └── what.py
│   │   ├── Crackers/
│   │   │   ├── __init__.py
│   │   │   ├── affine.py
│   │   │   ├── ascii_shift.py
│   │   │   ├── baconian.py
│   │   │   ├── caesar.py
│   │   │   ├── hash.py
│   │   │   ├── rot47.py
│   │   │   ├── soundex.py
│   │   │   ├── vigenere.py
│   │   │   ├── xandy.py
│   │   │   └── xortool.py
│   │   ├── Decoders/
│   │   │   ├── __init__.py
│   │   │   ├── a1z26.py
│   │   │   ├── atbash.py
│   │   │   ├── base58_bitcoin.py
│   │   │   ├── base58_flickr.py
│   │   │   ├── base58_ripple.py
│   │   │   ├── base62.py
│   │   │   ├── base64_url.py
│   │   │   ├── base65536.py
│   │   │   ├── base69.py
│   │   │   ├── base91.py
│   │   │   ├── bases.py
│   │   │   ├── baudot.py
│   │   │   ├── binary.py
│   │   │   ├── braille.py
│   │   │   ├── brainfuck.py
│   │   │   ├── decimal.py
│   │   │   ├── dna.py
│   │   │   ├── dtmf.py
│   │   │   ├── galactic.py
│   │   │   ├── gzip.py
│   │   │   ├── hexadecimal.py
│   │   │   ├── leetspeak.py
│   │   │   ├── letters.archive
│   │   │   ├── morse_code.py
│   │   │   ├── multi_tap.py
│   │   │   ├── octal.py
│   │   │   ├── reverse.py
│   │   │   ├── tap_code.py
│   │   │   ├── unicode.py
│   │   │   ├── url.py
│   │   │   ├── uuencode.py
│   │   │   └── z85.py
│   │   ├── Resources/
│   │   │   ├── __init__.py
│   │   │   ├── cipheydists.py
│   │   │   └── files.py
│   │   ├── Searchers/
│   │   │   ├── __init__.py
│   │   │   ├── astar.py
│   │   │   ├── atar.md
│   │   │   ├── ausearch.py
│   │   │   ├── imperfection.py
│   │   │   └── perfection.py
│   │   └── __init__.py
│   ├── ciphey.py
│   ├── common.py
│   ├── iface/
│   │   ├── __init__.py
│   │   ├── _config.py
│   │   ├── _fwd.py
│   │   ├── _modules.py
│   │   └── _registry.py
│   └── mathsHelper.py
├── codecov.yml
├── license
├── noxfile.py
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── brandon_interface.md
│   ├── cli.py
│   ├── dict.py
│   ├── enciphey.py
│   ├── generate_tests.py
│   ├── integration.py
│   ├── lukas.py
│   ├── speed_test.archive
│   ├── test_advanced_ciphers.py
│   ├── test_click.py
│   ├── test_click_printing.py
│   ├── test_main.py
│   ├── test_quick.py
│   └── test_regex.py
├── tools/
│   └── freq_analysis.py
└── translations/
    ├── de/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── fr/
    │   └── README.md
    ├── hu/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── id/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── it/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── nl/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── pt-br/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── ru/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    ├── th/
    │   ├── CODE_OF_CONDUCT.md
    │   ├── CONTRIBUTING.md
    │   └── README.md
    └── zh/
        ├── CODE_OF_CONDUCT.md
        ├── CONTRIBUTING.md
        └── README.md
Download .txt
SYMBOL INDEX (632 symbols across 76 files)

FILE: ciphey/basemods/Checkers/any.py
  class Any (line 7) | class Any(PolymorphicChecker):
    method getExpectedRuntime (line 10) | def getExpectedRuntime(self, text) -> float:
    method __init__ (line 13) | def __init__(self, config: Config):
    method check (line 16) | def check(self, text: str) -> Optional[str]:
    method getParams (line 20) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/brandon.py
  class Brandon (line 69) | class Brandon(Checker[str]):
    method getExpectedRuntime (line 81) | def getExpectedRuntime(self, text: T) -> float:
    method clean_text (line 88) | def clean_text(self, text: str) -> set:
    method checker (line 108) | def checker(self, text: str, threshold: float, text_length: int, var: ...
    method __init__ (line 165) | def __init__(self, config: Config):
    method check (line 181) | def check(self, text: str) -> Optional[str]:
    method calculateWhatChecker (line 241) | def calculateWhatChecker(self, length_text, key):
    method getParams (line 270) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/entropy.py
  class Entropy (line 10) | class Entropy(Checker[str]):
    method check (line 16) | def check(self, text: T) -> Optional[str]:
    method getExpectedRuntime (line 20) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 25) | def __init__(self, config: Config):
    method getParams (line 29) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/ezcheck.py
  class EzCheck (line 14) | class EzCheck(Checker[str]):
    method check (line 19) | def check(self, text: str) -> Optional[str]:
    method getExpectedRuntime (line 29) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 34) | def __init__(self, config: Config):
    method getParams (line 59) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/format.py
  class JsonChecker (line 11) | class JsonChecker(Checker[str]):
    method check (line 17) | def check(self, text: T) -> Optional[str]:
    method getExpectedRuntime (line 30) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 34) | def __init__(self, config: Config):
    method getParams (line 38) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/gtest.py
  class GTestChecker (line 10) | class GTestChecker(Checker[str]):
    method check (line 16) | def check(self, text: T) -> Optional[str]:
    method getExpectedRuntime (line 20) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/human.py
  class HumanChecker (line 11) | class HumanChecker(Checker[str]):
    method check (line 17) | def check(self, ctext: str) -> Optional[str]:
    method getExpectedRuntime (line 29) | def getExpectedRuntime(self, text: str) -> float:
    method getParams (line 33) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 36) | def __init__(self, config: Config):

FILE: ciphey/basemods/Checkers/quadgrams.py
  class Quadgrams (line 11) | class Quadgrams(Checker[str]):
    method check (line 17) | def check(self, ctext: T) -> Optional[str]:
    method getExpectedRuntime (line 42) | def getExpectedRuntime(self, text: T) -> float:
    method getParams (line 47) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 61) | def __init__(self, config: Config):

FILE: ciphey/basemods/Checkers/quorum.py
  class Quorum (line 6) | class Quorum(Generic[T], Checker[T]):
    method check (line 7) | def check(self, text: T) -> Optional[str]:
    method __init__ (line 19) | def __init__(self, config: Config):
    method getParams (line 36) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/regex.py
  class Regex (line 11) | class Regex(Checker[str]):
    method getExpectedRuntime (line 12) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 15) | def __init__(self, config: Config):
    method check (line 20) | def check(self, text: str) -> Optional[str]:
    method getParams (line 29) | def getParams() -> Optional[Dict[str, ParamSpec]]:
  class RegexList (line 40) | class RegexList(Checker[str]):
    method getExpectedRuntime (line 41) | def getExpectedRuntime(self, text: T) -> float:
    method __init__ (line 44) | def __init__(self, config: Config):
    method check (line 51) | def check(self, text: str) -> Optional[str]:
    method getParams (line 60) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Checkers/what.py
  class What (line 13) | class What(Checker[str]):
    method check (line 20) | def check(self, ctext: T) -> Optional[str]:
    method getExpectedRuntime (line 50) | def getExpectedRuntime(self, text: T) -> float:
    method getParams (line 55) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 58) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/affine.py
  class Affine (line 16) | class Affine(Cracker[str]):
    method getInfo (line 27) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 35) | def getTarget() -> str:
    method attemptCrack (line 38) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method plaintext_probability (line 74) | def plaintext_probability(self, translated: str) -> float:
    method decrypt (line 82) | def decrypt(self, text: str, a_inv: int, b: int, m: int) -> str:
    method decryptChar (line 90) | def decryptChar(self, char: str, a_inv: int, b: int, m: int) -> str:
    method getParams (line 105) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 119) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/ascii_shift.py
  class Ascii_shift (line 21) | class Ascii_shift(Cracker[str]):
    method getInfo (line 22) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 37) | def getTarget() -> str:
    method attemptCrack (line 40) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 76) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 96) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/baconian.py
  class Baconian (line 18) | class Baconian(Cracker[str]):
    method getInfo (line 19) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 27) | def getTarget() -> str:
    method attemptCrack (line 30) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 83) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 97) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/caesar.py
  class Caesar (line 22) | class Caesar(Cracker[str]):
    method getInfo (line 23) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 38) | def getTarget() -> str:
    method attemptCrack (line 41) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 86) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 111) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/hash.py
  function alpha (line 21) | def alpha(ctext, hashtype):
  function beta (line 25) | def beta(ctext, hashtype):
  function gamma (line 38) | def gamma(ctext, hashtype):
  function delta (line 51) | def delta(ctext, hashtype):
  function theta (line 55) | def theta(ctext, hashtype):
  function crack (line 80) | def crack(ctext):
  function threaded (line 84) | def threaded(ctext):
  class HashBuster (line 92) | class HashBuster(Cracker[str]):
    method getTarget (line 94) | def getTarget() -> str:
    method getParams (line 98) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method priority (line 102) | def priority() -> float:
    method getInfo (line 105) | def getInfo(self, ctext: T) -> CrackInfo:
    method attemptCrack (line 113) | def attemptCrack(self, ctext: T) -> List[CrackResult]:
    method __init__ (line 154) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/rot47.py
  class Rot47 (line 21) | class Rot47(Cracker[str]):
    method getInfo (line 22) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 37) | def getTarget() -> str:
    method attemptCrack (line 40) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 76) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 96) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/soundex.py
  class Soundex (line 19) | class Soundex(Cracker[str]):
    method getInfo (line 20) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 28) | def getTarget() -> str:
    method attemptCrack (line 31) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method sortlistwithdict (line 85) | def sortlistwithdict(self, listtosort, hashes):
    method getSentenceCombo (line 92) | def getSentenceCombo(
    method getParams (line 121) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 135) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/vigenere.py
  class Vigenere (line 22) | class Vigenere(Cracker[str]):
    method getInfo (line 23) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 80) | def getTarget() -> str:
    method crackOne (line 83) | def crackOne(
    method attemptCrack (line 106) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 157) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 195) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/xandy.py
  class Xandy (line 11) | class Xandy(Cracker[str]):
    method getInfo (line 12) | def getInfo(self, ctext: str) -> CrackInfo:
    method binary_to_ascii (line 20) | def binary_to_ascii(variant):
    method getTarget (line 36) | def getTarget() -> str:
    method attemptCrack (line 39) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 100) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 109) | def __init__(self, config: Config):

FILE: ciphey/basemods/Crackers/xortool.py
  class XorTool (line 21) | class XorTool(Cracker[str]):
    method getInfo (line 22) | def getInfo(self, ctext: str) -> CrackInfo:
    method getTarget (line 31) | def getTarget() -> str:
    method attemptCrack (line 34) | def attemptCrack(self, ctext: str) -> List[CrackResult]:
    method getParams (line 54) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method score_utility (line 69) | def score_utility() -> float:
    method __init__ (line 72) | def __init__(self, config: Config):

FILE: ciphey/basemods/Decoders/a1z26.py
  class A1z26 (line 11) | class A1z26(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 44) | def priority() -> float:
    method __init__ (line 47) | def __init__(self, config: Config):
    method getParams (line 51) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 55) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/atbash.py
  class Atbash (line 8) | class Atbash(Decoder[str]):
    method decode (line 9) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 32) | def priority() -> float:
    method __init__ (line 36) | def __init__(self, config: Config):
    method getParams (line 41) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 51) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base58_bitcoin.py
  class Base58_bitcoin (line 9) | class Base58_bitcoin(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base58_flickr.py
  class Base58_flickr (line 9) | class Base58_flickr(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 21) | def priority() -> float:
    method __init__ (line 25) | def __init__(self, config: Config):
    method getParams (line 29) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 33) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base58_ripple.py
  class Base58_ripple (line 9) | class Base58_ripple(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 22) | def priority() -> float:
    method __init__ (line 26) | def __init__(self, config: Config):
    method getParams (line 30) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 34) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base62.py
  class Base62 (line 9) | class Base62(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base64_url.py
  class Base64_url (line 8) | class Base64_url(Decoder[str]):
    method decode (line 9) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base65536.py
  class Base65536 (line 9) | class Base65536(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base69.py
  class Base69 (line 12) | class Base69(Decoder[str]):
    method decode (line 13) | def decode(self, ctext: T) -> Optional[U]:
    method decode_chunk (line 43) | def decode_chunk(self, s: str):
    method chars_to_byte (line 61) | def chars_to_byte(self, s: str):
    method priority (line 65) | def priority() -> float:
    method __init__ (line 70) | def __init__(self, config: Config):
    method getParams (line 75) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 85) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/base91.py
  class Base91 (line 9) | class Base91(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 24) | def __init__(self, config: Config):
    method getParams (line 28) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/bases.py
  function _dispatch (line 13) | def _dispatch(self: Any, ctext: str, func: Callable[[str], bytes]) -> Op...
  function gen_class (line 36) | def gen_class(name, decoder, priority, ns):

FILE: ciphey/basemods/Decoders/baudot.py
  class Baudot (line 8) | class Baudot(Decoder[str]):
    method decode (line 9) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 27) | def priority() -> float:
    method __init__ (line 30) | def __init__(self, config: Config):
    method getParams (line 35) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 45) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/binary.py
  class Binary (line 11) | class Binary(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method try_split (line 31) | def try_split(self, split_text: List[str]):
    method priority (line 48) | def priority() -> float:
    method __init__ (line 51) | def __init__(self, config: Config):
    method getParams (line 55) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 59) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/braille.py
  class Braille (line 10) | class Braille(Decoder[str]):
    method decode (line 11) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 50) | def priority() -> float:
    method __init__ (line 53) | def __init__(self, config: Config):
    method getParams (line 59) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 69) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/brainfuck.py
  class Brainfuck (line 12) | class Brainfuck(Decoder[str]):
    method decode (line 13) | def decode(self, ctext: T) -> Optional[U]:
    method bracemap_and_check (line 102) | def bracemap_and_check(self, program: str) -> Tuple[Optional[Dict], bo...
    method priority (line 150) | def priority() -> float:
    method __init__ (line 154) | def __init__(self, config: Config):
    method getParams (line 159) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 169) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/decimal.py
  class Decimal (line 11) | class Decimal(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 43) | def priority() -> float:
    method __init__ (line 46) | def __init__(self, config: Config):
    method getParams (line 50) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 54) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/dna.py
  class Dna (line 11) | class Dna(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 32) | def priority() -> float:
    method __init__ (line 35) | def __init__(self, config: Config):
    method getParams (line 40) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 50) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/dtmf.py
  class Dtmf (line 11) | class Dtmf(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 32) | def priority() -> float:
    method __init__ (line 35) | def __init__(self, config: Config):
    method getParams (line 40) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 50) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/galactic.py
  class Galactic (line 10) | class Galactic(Decoder[str]):
    method decode (line 11) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 61) | def priority() -> float:
    method __init__ (line 65) | def __init__(self, config: Config):
    method getParams (line 70) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 80) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/gzip.py
  class Gzip (line 8) | class Gzip(Decoder[bytes]):
    method decode (line 9) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 19) | def priority() -> float:
    method __init__ (line 23) | def __init__(self, config: Config):
    method getParams (line 27) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 31) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/hexadecimal.py
  class Hexadecimal (line 7) | class Hexadecimal(Decoder[str]):
    method decode (line 8) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 20) | def priority() -> float:
    method __init__ (line 23) | def __init__(self, config: Config):
    method getParams (line 27) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 31) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/leetspeak.py
  class Leetspeak (line 7) | class Leetspeak(Decoder[str]):
    method decode (line 8) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 14) | def priority() -> float:
    method __init__ (line 17) | def __init__(self, config: Config):
    method getParams (line 22) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 32) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/morse_code.py
  class Morse_code (line 10) | class Morse_code(Decoder[str]):
    method decode (line 19) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 78) | def priority() -> float:
    method __init__ (line 81) | def __init__(self, config: Config):
    method getParams (line 87) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 97) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/multi_tap.py
  class Multi_tap (line 7) | class Multi_tap(Decoder[str]):
    method decode (line 8) | def decode(self, ctext: T) -> Optional[U]:
    method valid_code_part (line 21) | def valid_code_part(code: str) -> bool:
    method decode_num_to_char (line 38) | def decode_num_to_char(number: str) -> str:
    method is_all_dup (line 43) | def is_all_dup(code):
    method calculate_index (line 47) | def calculate_index(number: str) -> int:
    method number_index_to_char (line 59) | def number_index_to_char(index_number: int) -> str:
    method get_index_from_first_digit (line 64) | def get_index_from_first_digit(first_digit: int) -> int:
    method priority (line 76) | def priority() -> float:
    method __init__ (line 79) | def __init__(self, config: Config):
    method getParams (line 84) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 88) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/octal.py
  class Octal (line 10) | class Octal(Decoder[str]):
    method decode (line 11) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 42) | def priority() -> float:
    method __init__ (line 45) | def __init__(self, config: Config):
    method getParams (line 49) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 53) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/reverse.py
  class Reverse (line 7) | class Reverse(Decoder[str]):
    method decode (line 8) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 12) | def priority() -> float:
    method __init__ (line 15) | def __init__(self, config: Config):
    method getParams (line 19) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 23) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/tap_code.py
  class Tap_code (line 9) | class Tap_code(Decoder[str]):
    method decode (line 10) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 24) | def priority() -> float:
    method __init__ (line 27) | def __init__(self, config: Config):
    method getParams (line 32) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 42) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/unicode.py
  class Utf8 (line 10) | class Utf8(Decoder[bytes]):
    method decode (line 11) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 28) | def priority() -> float:
    method __init__ (line 31) | def __init__(self, config: Config):
    method getParams (line 35) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 39) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/url.py
  class Url (line 11) | class Url(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 30) | def priority() -> float:
    method __init__ (line 33) | def __init__(self, config: Config):
    method getParams (line 37) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 41) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/uuencode.py
  class Uuencode (line 12) | class Uuencode(Decoder[str]):
    method decode (line 13) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 42) | def priority() -> float:
    method __init__ (line 46) | def __init__(self, config: Config):
    method getParams (line 50) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 54) | def getTarget() -> str:

FILE: ciphey/basemods/Decoders/z85.py
  class Z85 (line 11) | class Z85(Decoder[str]):
    method decode (line 12) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 28) | def priority() -> float:
    method __init__ (line 32) | def __init__(self, config: Config):
    method getParams (line 36) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method getTarget (line 40) | def getTarget() -> str:

FILE: ciphey/basemods/Resources/cipheydists.py
  class CipheyDists (line 19) | class CipheyDists(ResourceLoader):
    method whatResources (line 31) | def whatResources(self) -> Optional[Set[str]]:
    method getResource (line 35) | def getResource(self, name: str) -> Any:
    method __init__ (line 40) | def __init__(self, config: Config):
    method getParams (line 44) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Resources/files.py
  class Json (line 19) | class Json(ResourceLoader):
    method whatResources (line 20) | def whatResources(self) -> T:
    method getResource (line 24) | def getResource(self, name: str) -> T:
    method getName (line 31) | def getName() -> str:
    method getParams (line 35) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 38) | def __init__(self, config: Config):
  class Csv (line 46) | class Csv(Generic[T], ResourceLoader[T]):
    method whatResources (line 47) | def whatResources(self) -> Set[str]:
    method getResource (line 51) | def getResource(self, name: str) -> T:
    method getName (line 59) | def getName() -> str:
    method getParams (line 63) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method __init__ (line 66) | def __init__(self, config: Config):

FILE: ciphey/basemods/Searchers/astar.py
  class Node (line 4) | class Node:
    method __init__ (line 10) | def __init__(
    method __le__ (line 29) | def __le__(self, node2):
    method __lt__ (line 33) | def __lt__(self, node2):
    method append_edge (line 36) | def append_edge(self, edge):
    method get_edges (line 39) | def get_edges(self):
  class Graph (line 43) | class Graph:
    method __init__ (line 51) | def __init__(self, adjacency_list):
    method get_neighbors (line 58) | def get_neighbors(self, v):
    method heuristic (line 66) | def heuristic(self, n: Node):
    method a_star_algorithm (line 69) | def a_star_algorithm(self, start_node: Node, stop_node: Node):

FILE: ciphey/basemods/Searchers/ausearch.py
  class DuplicateNode (line 33) | class DuplicateNode(Exception):
  class AuSearchSuccessful (line 38) | class AuSearchSuccessful(Exception):
  class Node (line 44) | class Node:
    method decoding (line 51) | def decoding(
    method cracker (line 73) | def cracker(config: Config, edge_template: "Edge", result: CrackResult...
    method root (line 92) | def root(config: Config, ctext: Any):
    method get_path (line 98) | def get_path(self):
  class AusearchEdge (line 105) | class AusearchEdge:
    method __init__ (line 112) | def __init__(self, success_probability, success_time, failure_time):
  class AusearchResult (line 120) | class AusearchResult:
  function calculate_score (line 125) | def calculate_score(info: CrackInfo):
  class Edge (line 131) | class Edge:
  class PriorityWorkQueue (line 142) | class PriorityWorkQueue(Generic[PriorityType, T]):
    method add_work (line 146) | def add_work(self, priority: PriorityType, work: List[T]) -> None:
    method get_work (line 157) | def get_work(self) -> T:
    method get_work_chunk (line 165) | def get_work_chunk(self) -> List[T]:
    method empty (line 172) | def empty(self):
    method __init__ (line 175) | def __init__(self):
  class AuSearch (line 181) | class AuSearch(Searcher):
    method get_crackers_for (line 186) | def get_crackers_for(t: type):
    method get_decoders_for (line 190) | def get_decoders_for(self, t: type):
    method expand_crackers (line 199) | def expand_crackers(self, node: Node) -> None:
    method expand_decodings (line 221) | def expand_decodings(self, node: Node) -> None:
    method recursive_expand (line 239) | def recursive_expand(self, node: Node, nested: bool = True) -> None:
    method search (line 251) | def search(self, ctext: Any) -> Optional[SearchResult]:
    method __init__ (line 302) | def __init__(self, config: Config):
    method getParams (line 322) | def getParams() -> Optional[Dict[str, ParamSpec]]:

FILE: ciphey/basemods/Searchers/imperfection.py
  class Imperfection (line 4) | class Imperfection:
    method __init__ (line 50) | def __init__(self):
    method findBestNode (line 53) | def findBestNode(self, nodes):
    method aStar (line 153) | def aStar(self, graph, current, end):
  class Node (line 197) | class Node:
    method __init__ (line 203) | def __init__(self, h):
    method __le__ (line 208) | def __le__(self, node2):
    method __lt__ (line 212) | def __lt__(self, node2):

FILE: ciphey/basemods/Searchers/perfection.py
  class Perfection (line 9) | class Perfection(AuSearch):
    method getParams (line 11) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method findBestNode (line 14) | def findBestNode(self, nodes: Set[Node]) -> Node:
    method __init__ (line 17) | def __init__(self, config: Config):

FILE: ciphey/ciphey.py
  function decrypt (line 31) | def decrypt(config: iface.Config, ctext: Any) -> Union[str, bytes]:
  function get_name (line 42) | def get_name(ctx, param, value):
  function print_help (line 51) | def print_help(ctx):
  function main (line 133) | def main(**kwargs):

FILE: ciphey/common.py
  function id_lambda (line 5) | def id_lambda(value: Any):
  function fix_case (line 12) | def fix_case(target: str, base: str) -> str:

FILE: ciphey/iface/_config.py
  class Cache (line 15) | class Cache:
    method __init__ (line 18) | def __init__(self):
    method mark_ctext (line 21) | def mark_ctext(self, ctext: Any) -> bool:
    method get_or_update (line 35) | def get_or_update(self, ctext: Any, keyname: str, get_value: Callable[...
    method try_get (line 46) | def try_get(self, ctext: Any, keyname: str):
  function split_resource_name (line 50) | def split_resource_name(full_name: str) -> (str, str):
  class Config (line 54) | class Config:
    method __init__ (line 55) | def __init__(self):
    method get_default_dir (line 69) | def get_default_dir() -> str:
    method merge_dict (line 72) | def merge_dict(self, config_file: Optional[Dict[str, Any]]):
    method load_file (line 78) | def load_file(
    method instantiate (line 90) | def instantiate(self, t: type) -> Any:
    method __call__ (line 102) | def __call__(self, t: type) -> Any:
    method update (line 105) | def update(self, attrname: str, value: Optional[Any]):
    method update_param (line 109) | def update_param(self, owner: str, name: str, value: Optional[Any]):
    method update_format (line 120) | def update_format(self, value: Optional[str]):
    method load_objs (line 124) | def load_objs(self):
    method update_log_level (line 138) | def update_log_level(self, verbosity: Optional[int]):
    method load_modules (line 161) | def load_modules(self):
    method complete_config (line 171) | def complete_config(self) -> "Config":
    method get_resource (line 178) | def get_resource(self, res_name: str, t: Optional[Type] = None) -> Any:
    method set_verbosity (line 189) | def set_verbosity(self, i):
    method set_spinner (line 193) | def set_spinner(self, spinner):
    method pause_spinner_handle (line 196) | def pause_spinner_handle(self):
    method library_default (line 211) | def library_default():
    method __str__ (line 215) | def __str__(self):

FILE: ciphey/iface/_modules.py
  class ParamSpec (line 17) | class ParamSpec(NamedTuple):
  class ConfigurableModule (line 36) | class ConfigurableModule(ABC):
    method getParams (line 39) | def getParams() -> Optional[Dict[str, ParamSpec]]:
    method _checkParams (line 45) | def _checkParams(self):
    method _params (line 73) | def _params(self):
    method _config (line 76) | def _config(self):
    method __init__ (line 80) | def __init__(self, config: Config):
  class Targeted (line 87) | class Targeted(ABC):
    method getTarget (line 90) | def getTarget() -> str:
  class PolymorphicChecker (line 95) | class PolymorphicChecker(ConfigurableModule):
    method check (line 97) | def check(self, text) -> Optional[str]:
    method getExpectedRuntime (line 102) | def getExpectedRuntime(self, text) -> float:
    method __call__ (line 105) | def __call__(self, *args):
    method __init__ (line 109) | def __init__(self, config: Config):
  class Checker (line 113) | class Checker(Generic[T], ConfigurableModule):
    method check (line 115) | def check(self, text: T) -> Optional[str]:
    method getExpectedRuntime (line 120) | def getExpectedRuntime(self, text: T) -> float:
    method __call__ (line 123) | def __call__(self, *args):
    method __init__ (line 127) | def __init__(self, config: Config):
    method convert (line 131) | def convert(cls, expected: Set[type]):
  class Decoder (line 172) | class Decoder(Generic[T], ConfigurableModule, Targeted):
    method decode (line 176) | def decode(self, ctext: T) -> Optional[U]:
    method priority (line 181) | def priority() -> float:
    method __call__ (line 185) | def __call__(self, *args):
    method __init__ (line 189) | def __init__(self, config: Config):
  class DecoderComparer (line 193) | class DecoderComparer:
    method __le__ (line 196) | def __le__(self, other: "DecoderComparer"):
    method __ge__ (line 199) | def __ge__(self, other: "DecoderComparer"):
    method __lt__ (line 202) | def __lt__(self, other: "DecoderComparer"):
    method __gt__ (line 205) | def __gt__(self, other: "DecoderComparer"):
    method __init__ (line 208) | def __init__(self, value: Type[Decoder]):
    method __repr__ (line 211) | def __repr__(self):
  class CrackResult (line 215) | class CrackResult(NamedTuple):
  class CrackInfo (line 223) | class CrackInfo(NamedTuple):
  class Cracker (line 229) | class Cracker(Generic[T], ConfigurableModule, Targeted):
    method getInfo (line 231) | def getInfo(self, ctext: T) -> CrackInfo:
    method attemptCrack (line 236) | def attemptCrack(self, ctext: T) -> List[CrackResult]:
    method __call__ (line 243) | def __call__(self, *args):
    method __init__ (line 247) | def __init__(self, config: Config):
  class ResourceLoader (line 251) | class ResourceLoader(Generic[T], ConfigurableModule):
    method whatResources (line 253) | def whatResources(self) -> Optional[Set[str]]:
    method getResource (line 265) | def getResource(self, name: str) -> T:
    method __call__ (line 273) | def __call__(self, *args):
    method __getitem__ (line 276) | def __getitem__(self, *args):
    method __init__ (line 280) | def __init__(self, config: Config):
  class SearchLevel (line 284) | class SearchLevel(NamedTuple):
    method input (line 289) | def input(ctext: Any):
  class SearchResult (line 293) | class SearchResult(NamedTuple):
  class Searcher (line 298) | class Searcher(ConfigurableModule):
    method search (line 302) | def search(self, ctext: Any) -> Optional[SearchResult]:
    method __init__ (line 307) | def __init__(self, config: Config):
  function pretty_search_results (line 311) | def pretty_search_results(res: SearchResult, display_intermediate: bool ...

FILE: ciphey/iface/_registry.py
  class Registry (line 12) | class Registry:
    method _register_one (line 23) | def _register_one(self, input_type, module_base, module_args):
    method _real_register (line 34) | def _real_register(self, input_type: type, *args) -> Type:
    method register (line 119) | def register(self, input_type):
    method register_multi (line 122) | def register_multi(self, *x):
    method __getitem__ (line 125) | def __getitem__(self, i: type) -> Optional[Any]:
    method get_named (line 137) | def get_named(self, name: str, type_constraint: Type = None) -> Any:
    method get_targeted (line 143) | def get_targeted(
    method get_all_names (line 151) | def get_all_names(self) -> List[str]:
    method __str__ (line 154) | def __str__(self):

FILE: ciphey/mathsHelper.py
  class mathsHelper (line 23) | class mathsHelper:
    method __init__ (line 26) | def __init__(self):
    method gcd (line 32) | def gcd(a, b) -> int:
    method mod_inv (line 51) | def mod_inv(a: int, m: int) -> Optional[int]:
    method percentage (line 68) | def percentage(part: float, whole: float) -> float:
    method sort_prob_table (line 86) | def sort_prob_table(self, prob_table: dict) -> dict:
    method new_sort (line 157) | def new_sort(new_dict: dict) -> dict:
    method is_ascii (line 179) | def is_ascii(s: str) -> bool:
    method strip_punctuation (line 196) | def strip_punctuation(text: str) -> str:

FILE: noxfile.py
  function install_with_constraints (line 14) | def install_with_constraints(session: Session, *args: str, **kwargs: Any...
  function black (line 40) | def black(session):
  function coverage (line 47) | def coverage(session: Session) -> None:
  function docs (line 57) | def docs(session: Session) -> None:
  function tests (line 64) | def tests(session):

FILE: tests/dict.py
  class testDictionary (line 14) | class testDictionary(unittest.TestCase):
    method test_english_yes (line 15) | def test_english_yes(self):
    method test_english_yes_two (line 22) | def test_english_yes_two(self):
    method test_english_false (line 30) | def test_english_false(self):
    method test_english_false_two (line 35) | def test_english_false_two(self):
    method test_english_perfect (line 50) | def test_english_perfect(self):

FILE: tests/enciphey.py
  class encipher (line 15) | class encipher:
    method __init__ (line 19) | def __init__(self):  # pragma: no cover
    method read_text (line 25) | def read_text(self):  # pragma: no cover
    method getRandomSentence (line 31) | def getRandomSentence(self, size):  # pragma: no cover
    method getRandomEncryptedSentence (line 36) | def getRandomEncryptedSentence(self, size):  # pragma: no cover
  class encipher_crypto (line 43) | class encipher_crypto:  # pragma: no cover
    method __init__ (line 54) | def __init__(self):  # pragma: no cover
    method random_key (line 74) | def random_key(self, text) -> str:  # pragma: no cover
    method random_string (line 81) | def random_string(self, length) -> str:  # pragma: no cover
    method randomEncrypt (line 84) | def randomEncrypt(self, text: str) -> str:  # pragma: no cover
    method Base64 (line 92) | def Base64(self, text: str) -> str:  # pragma: no cover
    method Caesar (line 102) | def Caesar(self, s, k):  # pragma: no cover
    method apply_rotation (line 110) | def apply_rotation(self, c, facr):  # pragma: no cover
    method Base32 (line 117) | def Base32(self, text: str) -> str:  # pragma: no cover
    method Base16 (line 127) | def Base16(self, text: str) -> str:  # pragma: no cover
    method Binary (line 137) | def Binary(self, text: str) -> str:  # pragma: no cover
    method Ascii (line 141) | def Ascii(self, text: str) -> str:  # pragma: no cover
    method Hex (line 145) | def Hex(self, text: str) -> str:  # pragma: no cover
    method MorseCode (line 148) | def MorseCode(self, text: str) -> str:  # pragma: :wno cover
    method Reverse (line 161) | def Reverse(self, text: str) -> str:
    method Vigenere (line 164) | def Vigenere(self, plaintext):
    method vig_key (line 168) | def vig_key(self, msg, key):
    method base58_bitcoin (line 179) | def base58_bitcoin(self, text: str):
    method base58_ripple (line 182) | def base58_ripple(self, text: str):
    method b62 (line 187) | def b62(self, text: str):

FILE: tests/generate_tests.py
  class test_generator (line 35) | class test_generator:
    method __init__ (line 36) | def __init__(self):
    method main (line 40) | def main(self):
    method make_test_true_template (line 54) | def make_test_true_template(self, cipher):
    method make_test_lc_true_template (line 63) | def make_test_lc_true_template(self, cipher):
    method randomString (line 75) | def randomString(self, stringLength):

FILE: tests/integration.py
  class testIntegration (line 11) | class testIntegration(unittest.TestCase):
    method test_basics (line 16) | def test_basics(self):
    method test_basics_german (line 23) | def test_basics_german(self):
    method test_basics_quickbrownfox (line 28) | def test_basics_quickbrownfox(self):
    method test_basics_quickbrownfox (line 36) | def test_basics_quickbrownfox(self):
    method test_chi_maxima_true (line 44) | def test_chi_maxima_true(self):
    method test_integration_unusual_one (line 71) | def test_integration_unusual_one(self):
    method test_integration_unusual_two (line 76) | def test_integration_unusual_two(self):
    method test_integration_unusual_three (line 81) | def test_integration_unusual_three(self):
    method test_integration_unusual_three (line 86) | def test_integration_unusual_three(self):
    method test_integration_unusual_four (line 91) | def test_integration_unusual_four(self):
    method test_integration_unusual_five (line 96) | def test_integration_unusual_five(self):
    method test_integration_unusual_7 (line 101) | def test_integration_unusual_7(self):
    method test_integration_unusual_7 (line 108) | def test_integration_unusual_7(self):
    method test_integration_addition (line 113) | def test_integration_addition(self):
    method test_integration_charlesBabbage (line 130) | def test_integration_charlesBabbage(self):

FILE: tests/lukas.py
  class galactic_encode (line 6) | class galactic_encode:
    method __init__ (line 11) | def __init__(self, text: str):
    method encode (line 18) | def encode(self):
  class atbash_encode (line 27) | class atbash_encode:
    method __init__ (line 32) | def __init__(self, text: str):
    method encode (line 38) | def encode(self):
  class XY_encrypt (line 50) | class XY_encrypt:
    method __init__ (line 60) | def __init__(
    method randomizer (line 74) | def randomizer(self):
    method to_binary (line 81) | def to_binary(self):
    method encrypt (line 84) | def encrypt(self):

FILE: tests/test_advanced_ciphers.py
  function test_xor (line 11) | def test_xor():
  function test_xor_tui_multi_byte (line 17) | def test_xor_tui_multi_byte(mock_click):
  function test_xor_tui (line 27) | def test_xor_tui(mock_click):
  function test_xor_tui_verbose_mode_doesnt_break (line 36) | def test_xor_tui_verbose_mode_doesnt_break(mock_click):
  function test_xor_atbash (line 45) | def test_xor_atbash():

FILE: tests/test_click.py
  function test_hello_world (line 7) | def test_hello_world():
  function test_ip_address (line 14) | def test_ip_address():
  function test_quick_visual_output (line 22) | def test_quick_visual_output(mock_click):

FILE: tests/test_click_printing.py
  function test_fix_for_655 (line 8) | def test_fix_for_655(mock_click):

FILE: tests/test_main.py
  function test_a1z26 (line 9) | def test_a1z26():
  function test_affine (line 17) | def test_affine():
  function test_ascii_shift (line 25) | def test_ascii_shift():
  function test_atbash (line 33) | def test_atbash():
  function test_baconian_complete_variant (line 41) | def test_baconian_complete_variant():
  function test_baconian_standard_variant (line 49) | def test_baconian_standard_variant():
  function test_base32 (line 57) | def test_base32():
  function test_base58_bitcoin (line 65) | def test_base58_bitcoin():
  function test_base58_ripple (line 73) | def test_base58_ripple():
  function test_base62 (line 81) | def test_base62():
  function test_base64 (line 89) | def test_base64():
  function test_base69 (line 98) | def test_base69():
  function test_base85 (line 106) | def test_base85():
  function test_base91 (line 114) | def test_base91():
  function test_baudot (line 122) | def test_baudot():
  function test_binary (line 130) | def test_binary():
  function test_binary_base64_caesar (line 142) | def test_binary_base64_caesar():
  function test_braille (line 151) | def test_braille():
  function test_brainfuck (line 159) | def test_brainfuck():
  function test_brandon (line 167) | def test_brandon():
  function test_caesar (line 175) | def test_caesar():
  function test_decimal (line 183) | def test_decimal():
  function test_dna (line 191) | def test_dna():
  function test_dtmf (line 199) | def test_dtmf():
  function test_galactic (line 207) | def test_galactic():
  function test_galactic_Xproblem (line 215) | def test_galactic_Xproblem():
  function test_gzip (line 223) | def test_gzip():
  function test_hexadecimal (line 231) | def test_hexadecimal():
  function test_json_problem (line 240) | def test_json_problem():
  function test_leetspeak (line 248) | def test_leetspeak():
  function test_morse_code (line 256) | def test_morse_code():
  function test_multi_tap (line 264) | def test_multi_tap():
  function test_new_line_at_start_returns (line 272) | def test_new_line_at_start_returns():
  function test_new_line_strip_and_return (line 280) | def test_new_line_strip_and_return():
  function test_octal (line 288) | def test_octal():
  function test_plaintext (line 296) | def test_plaintext():
  function test_quadgrams_messed_up_spacing (line 301) | def test_quadgrams_messed_up_spacing():
  function test_quadgrams_no_spaces (line 311) | def test_quadgrams_no_spaces():
  function test_quadgrams_space_between_every_letter (line 319) | def test_quadgrams_space_between_every_letter():
  function test_reversed_text (line 330) | def test_reversed_text():
  function test_rot47 (line 338) | def test_rot47():
  function test_soundex (line 346) | def test_soundex():
  function test_tap_code (line 354) | def test_tap_code():
  function test_url (line 362) | def test_url():
  function test_uuencode (line 370) | def test_uuencode():
  function test_vigenere (line 383) | def test_vigenere():
  function test_xandy (line 392) | def test_xandy():

FILE: tests/test_quick.py
  function test_quick_base32 (line 13) | def test_quick_base32():
  function test_quick_base58_ripple (line 21) | def test_quick_base58_ripple():
  function test_quick_greppable_works_with_ip_address (line 29) | def test_quick_greppable_works_with_ip_address():
  function test_quick_visual_output (line 37) | def test_quick_visual_output(mock_click):

FILE: tests/test_regex.py
  function test_regex_ip (line 7) | def test_regex_ip():
  function test_regex_domain (line 15) | def test_regex_domain():
  function test_regex_bitcoin (line 23) | def test_regex_bitcoin():
Condensed preview — 144 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (628K chars).
[
  {
    "path": ".all-contributorsrc",
    "chars": 9080,
    "preview": "{\n  \"files\": [\n    \"README.md\"\n  ],\n  \"imageSize\": 100,\n  \"commit\": false,\n  \"contributors\": [\n    {\n      \"login\": \"cyc"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 145,
    "preview": "# These are supported funding model platforms\n\ngithub: bee-san\ncustom: [\"https://www.buymeacoffee.com/beecodes\", \"https:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1535,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\n\n---\n\n**⚠️IMPORTANT⚠️ if you do not"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 28,
    "preview": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 374,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: brandonskerri"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/maintenance_suggestion.md",
    "chars": 374,
    "preview": "---\nname: Maintenance suggestion\nabout: Suggest refactoring/restructuring that would help\ntitle: ''\nlabels: maintenance\n"
  },
  {
    "path": ".github/config.yml",
    "chars": 25,
    "preview": "todo:\n  keyword: \"@TODO\"\n"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 202,
    "preview": "version: 2\nupdates:\n- package-ecosystem: pip\n  directory: \"/\"\n  schedule:\n    interval: daily\n  open-pull-requests-limit"
  },
  {
    "path": ".github/lock.yml",
    "chars": 1154,
    "preview": "# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app\n\n# Number of days of inactivity before a "
  },
  {
    "path": ".github/release-drafter.yml",
    "chars": 44,
    "preview": "template: |\n  ## What’s Changed\n\n  $CHANGES\n"
  },
  {
    "path": ".github/workflows/coverage.yml",
    "chars": 941,
    "preview": "name: coverage\non: [push, pull_request]\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n       "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 455,
    "preview": "# .github/workflows/release.yml\nname: Release\non:\n  release:\n    types: [published]\njobs:\n  release:\n    runs-on: ubuntu"
  },
  {
    "path": ".github/workflows/releasetestpypi.yml",
    "chars": 675,
    "preview": "# .github/workflows/test-pypi.yml\nname: TestPyPI\non:\n  push:\n    branches:\n      - master\njobs:\n  test_pypi:\n    runs-on"
  },
  {
    "path": ".github/workflows/terminaltest.yml",
    "chars": 1263,
    "preview": "on: pull_request\nname: Ciphey terminal test\njobs:\n  terminal_test:\n    name: On ubuntu-latest with python\n    runs-on: u"
  },
  {
    "path": ".github/workflows/tests2.yml",
    "chars": 756,
    "preview": "name: Tests\non: [push, pull_request]\njobs:\n  tests:\n    strategy:\n      fail-fast: false\n      matrix:\n        python-ve"
  },
  {
    "path": ".gitignore",
    "chars": 3830,
    "preview": "\r\n# Created by https://www.gitignore.io/api/git,python,virtualenv\r\n# Edit at https://www.gitignore.io/?templates=git,pyt"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3351,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3723,
    "preview": "<p align=\"center\">\nTranslations <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.m"
  },
  {
    "path": "Pictures_for_README/.gitattributes",
    "chars": 60,
    "preview": "render1596301769504.gif filter=lfs diff=lfs merge=lfs -text\n"
  },
  {
    "path": "README.md",
    "chars": 24050,
    "preview": "<p align=\"center\">\nTranslations <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 D"
  },
  {
    "path": "ciphey/__init__.py",
    "chars": 66,
    "preview": "from . import basemods, common, iface\nfrom .ciphey import decrypt\n"
  },
  {
    "path": "ciphey/__main__.py",
    "chars": 1270,
    "preview": "#! /usr/bin/env python3\n\n\"\"\"\nCiphey: https://github.com/Ciphey/Ciphey\n\"\"\"\n\nimport platform\nimport sys\n\nif __name__ == \"_"
  },
  {
    "path": "ciphey/basemods/Checkers/__init__.py",
    "chars": 83,
    "preview": "from . import any, brandon, ezcheck, format, human, quadgrams, quorum, regex, what\n"
  },
  {
    "path": "ciphey/basemods/Checkers/any.py",
    "chars": 542,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Config, ParamSpec, PolymorphicChecker, registry\n\n\n@registry."
  },
  {
    "path": "ciphey/basemods/Checkers/brandon.py",
    "chars": 12337,
    "preview": "\"\"\"\r\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\r\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\r\n██║     ██║██████╔╝████"
  },
  {
    "path": "ciphey/basemods/Checkers/entropy.py",
    "chars": 689,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Checker"
  },
  {
    "path": "ciphey/basemods/Checkers/ezcheck.py",
    "chars": 1804,
    "preview": "from typing import Dict, List, Optional\n\nfrom ciphey.iface import Checker, Config, ParamSpec, T, registry\n\nfrom .brandon"
  },
  {
    "path": "ciphey/basemods/Checkers/format.py",
    "chars": 956,
    "preview": "import json\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface im"
  },
  {
    "path": "ciphey/basemods/Checkers/gtest.py",
    "chars": 663,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Checker"
  },
  {
    "path": "ciphey/basemods/Checkers/human.py",
    "chars": 1005,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Checker, Config, ParamSpec, registry\nfrom rich.console impor"
  },
  {
    "path": "ciphey/basemods/Checkers/quadgrams.py",
    "chars": 2174,
    "preview": "import logging\nimport re\nfrom math import log10\nfrom typing import Dict, Optional\n\nfrom ciphey.iface import Checker, Con"
  },
  {
    "path": "ciphey/basemods/Checkers/quorum.py",
    "chars": 1542,
    "preview": "from typing import Dict, Generic, Optional\n\nfrom ciphey.iface import Checker, Config, ParamSpec, T, _registry\n\n\nclass Qu"
  },
  {
    "path": "ciphey/basemods/Checkers/regex.py",
    "chars": 2282,
    "preview": "import re\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface impo"
  },
  {
    "path": "ciphey/basemods/Checkers/what.py",
    "chars": 2108,
    "preview": "from typing import Dict, Optional\r\n\r\nfrom ciphey.iface import Checker, Config, ParamSpec, T, registry\r\nimport logging\r\nf"
  },
  {
    "path": "ciphey/basemods/Crackers/__init__.py",
    "chars": 135,
    "preview": "from . import (\n    affine,\n    ascii_shift,\n    baconian,\n    caesar,\n    rot47,\n    soundex,\n    vigenere,\n    xandy,\n"
  },
  {
    "path": "ciphey/basemods/Crackers/affine.py",
    "chars": 5052,
    "preview": "# Community\n# by https://github.com/Ozzyz\n\nfrom typing import Dict, List, Optional\n\nimport cipheycore\nimport logging\nfro"
  },
  {
    "path": "ciphey/basemods/Crackers/ascii_shift.py",
    "chars": 3597,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/basemods/Crackers/baconian.py",
    "chars": 3253,
    "preview": "import re\nfrom typing import Dict, List, Optional\n\nfrom ciphey.iface import (\n    Config,\n    Cracker,\n    CrackInfo,\n  "
  },
  {
    "path": "ciphey/basemods/Crackers/caesar.py",
    "chars": 4034,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/basemods/Crackers/hash.py",
    "chars": 4389,
    "preview": "\"\"\"\nThis is Hashbuster but slightly modified to work with Ciphey.\nWhy reinvent the wheel?\nChanges (that I can remember)\n"
  },
  {
    "path": "ciphey/basemods/Crackers/rot47.py",
    "chars": 3440,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/basemods/Crackers/soundex.py",
    "chars": 4628,
    "preview": "import re\nfrom typing import Dict, List, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.ifac"
  },
  {
    "path": "ciphey/basemods/Crackers/vigenere.py",
    "chars": 7344,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/basemods/Crackers/xandy.py",
    "chars": 4249,
    "preview": "import re\nfrom typing import Dict, List, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.ifac"
  },
  {
    "path": "ciphey/basemods/Crackers/xortool.py",
    "chars": 2190,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/basemods/Decoders/__init__.py",
    "chars": 372,
    "preview": "from . import (\n    a1z26,\n    atbash,\n    base58_bitcoin,\n    base58_ripple,\n    base62,\n    base69,\n    base91,\n    ba"
  },
  {
    "path": "ciphey/basemods/Decoders/a1z26.py",
    "chars": 1687,
    "preview": "import re\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface impo"
  },
  {
    "path": "ciphey/basemods/Decoders/atbash.py",
    "chars": 1815,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.common import fix_case\nfrom ciphey.iface import Config, Decoder, ParamSpe"
  },
  {
    "path": "ciphey/basemods/Decoders/base58_bitcoin.py",
    "chars": 796,
    "preview": "from typing import Dict, Optional\n\nimport base58\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n"
  },
  {
    "path": "ciphey/basemods/Decoders/base58_flickr.py",
    "chars": 907,
    "preview": "from typing import Dict, Optional\n\nimport base58\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n"
  },
  {
    "path": "ciphey/basemods/Decoders/base58_ripple.py",
    "chars": 856,
    "preview": "from typing import Dict, Optional\n\nimport base58\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n"
  },
  {
    "path": "ciphey/basemods/Decoders/base62.py",
    "chars": 772,
    "preview": "from typing import Dict, Optional\n\nimport base62\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n"
  },
  {
    "path": "ciphey/basemods/Decoders/base64_url.py",
    "chars": 856,
    "preview": "import base64\nfrom typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n@"
  },
  {
    "path": "ciphey/basemods/Decoders/base65536.py",
    "chars": 782,
    "preview": "from typing import Dict, Optional\n\nimport base65536\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry"
  },
  {
    "path": "ciphey/basemods/Decoders/base69.py",
    "chars": 2749,
    "preview": "# Translated to Python and adapted for Ciphey from the JS original at https://github.com/pshihn/base69\n\n\nimport re\nfrom "
  },
  {
    "path": "ciphey/basemods/Decoders/base91.py",
    "chars": 767,
    "preview": "from typing import Dict, Optional\n\nimport base91\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n"
  },
  {
    "path": "ciphey/basemods/Decoders/bases.py",
    "chars": 1475,
    "preview": "import base64\nimport types\nfrom typing import Any, Callable, Optional\n\nimport logging\nfrom rich.logging import RichHandl"
  },
  {
    "path": "ciphey/basemods/Decoders/baudot.py",
    "chars": 1367,
    "preview": "import re\nfrom typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, reg"
  },
  {
    "path": "ciphey/basemods/Decoders/binary.py",
    "chars": 1613,
    "preview": "import re\nfrom typing import Dict, List, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.ifac"
  },
  {
    "path": "ciphey/basemods/Decoders/braille.py",
    "chars": 2261,
    "preview": "import re\nfrom typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, reg"
  },
  {
    "path": "ciphey/basemods/Decoders/brainfuck.py",
    "chars": 5841,
    "preview": "import re\nimport time\nfrom typing import Dict, Optional, Tuple\n\nimport logging\nfrom rich.logging import RichHandler\n\nfro"
  },
  {
    "path": "ciphey/basemods/Decoders/decimal.py",
    "chars": 1666,
    "preview": "import re\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface impo"
  },
  {
    "path": "ciphey/basemods/Decoders/dna.py",
    "chars": 1436,
    "preview": "import re\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface impo"
  },
  {
    "path": "ciphey/basemods/Decoders/dtmf.py",
    "chars": 1450,
    "preview": "import re\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface impo"
  },
  {
    "path": "ciphey/basemods/Decoders/galactic.py",
    "chars": 2998,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Config,"
  },
  {
    "path": "ciphey/basemods/Decoders/gzip.py",
    "chars": 783,
    "preview": "import zlib\nfrom typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n@re"
  },
  {
    "path": "ciphey/basemods/Decoders/hexadecimal.py",
    "chars": 771,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n@registry.regis"
  },
  {
    "path": "ciphey/basemods/Decoders/leetspeak.py",
    "chars": 911,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry\n\n\n@r"
  },
  {
    "path": "ciphey/basemods/Decoders/letters.archive",
    "chars": 689,
    "preview": "\"\"\"\nNot yet implemented.\n\"\"\"\nclass letters:\n\n    \"\"\"Deals with Nato Strings / first letter of every word\"\"\"\n\n    def __i"
  },
  {
    "path": "ciphey/basemods/Decoders/morse_code.py",
    "chars": 3349,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Config,"
  },
  {
    "path": "ciphey/basemods/Decoders/multi_tap.py",
    "chars": 2340,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n@registry.regis"
  },
  {
    "path": "ciphey/basemods/Decoders/octal.py",
    "chars": 1610,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Config,"
  },
  {
    "path": "ciphey/basemods/Decoders/reverse.py",
    "chars": 535,
    "preview": "from typing import Dict, Optional\n\nfrom ciphey.iface import Config, Decoder, ParamSpec, T, U, registry\n\n\n@registry.regis"
  },
  {
    "path": "ciphey/basemods/Decoders/tap_code.py",
    "chars": 1204,
    "preview": "# by https://github.com/RustyDucky and https://github.com/lukasgabriel\n\nfrom typing import Dict, Optional\n\nfrom ciphey.i"
  },
  {
    "path": "ciphey/basemods/Decoders/unicode.py",
    "chars": 968,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.iface import Config,"
  },
  {
    "path": "ciphey/basemods/Decoders/url.py",
    "chars": 1054,
    "preview": "from typing import Dict, Optional\nfrom urllib.parse import unquote_plus\n\nimport logging\nfrom rich.logging import RichHan"
  },
  {
    "path": "ciphey/basemods/Decoders/uuencode.py",
    "chars": 2033,
    "preview": "from binascii import a2b_uu\nfrom codecs import decode\nfrom typing import Dict, Optional\n\nimport logging\nfrom rich.loggin"
  },
  {
    "path": "ciphey/basemods/Decoders/z85.py",
    "chars": 1039,
    "preview": "from typing import Dict, Optional\n\nimport logging\nfrom rich.logging import RichHandler\nfrom zmq.utils import z85\n\nfrom c"
  },
  {
    "path": "ciphey/basemods/Resources/__init__.py",
    "chars": 33,
    "preview": "from . import cipheydists, files\n"
  },
  {
    "path": "ciphey/basemods/Resources/cipheydists.py",
    "chars": 1220,
    "preview": "from functools import lru_cache\nfrom typing import Any, Dict, Optional, Set\n\nimport cipheydists\nimport logging\n\nfrom cip"
  },
  {
    "path": "ciphey/basemods/Resources/files.py",
    "chars": 2063,
    "preview": "import csv\nimport json\nfrom functools import lru_cache\nfrom typing import Dict, Generic, Optional, Set\n\nfrom ciphey.ifac"
  },
  {
    "path": "ciphey/basemods/Searchers/__init__.py",
    "chars": 23,
    "preview": "from . import ausearch\n"
  },
  {
    "path": "ciphey/basemods/Searchers/astar.py",
    "chars": 5588,
    "preview": "import cipheycore\n\n\nclass Node:\n    \"\"\"\n    A node has a value associated with it\n    Calculated from the heuristic\n    "
  },
  {
    "path": "ciphey/basemods/Searchers/atar.md",
    "chars": 6249,
    "preview": "function reconstruct_path(cameFrom, current)\n    total_path := {current}\n    while current in cameFrom.Keys:\n        cur"
  },
  {
    "path": "ciphey/basemods/Searchers/ausearch.py",
    "chars": 11472,
    "preview": "import bisect\nimport distutils\nimport math\nfrom copy import copy\nfrom dataclasses import dataclass\nfrom functools import"
  },
  {
    "path": "ciphey/basemods/Searchers/imperfection.py",
    "chars": 7483,
    "preview": "import heapq\n\n\nclass Imperfection:\n    \"\"\"The graph is a Node: [List of nodes]\n    Where each item in the list of nodes "
  },
  {
    "path": "ciphey/basemods/Searchers/perfection.py",
    "chars": 435,
    "preview": "from typing import Dict, Optional, Set\n\nfrom ciphey.iface import Config, ParamSpec, registry\n\nfrom .ausearch import AuSe"
  },
  {
    "path": "ciphey/basemods/__init__.py",
    "chars": 65,
    "preview": "from . import Checkers, Crackers, Decoders, Resources, Searchers\n"
  },
  {
    "path": "ciphey/ciphey.py",
    "chars": 8252,
    "preview": "\"\"\"\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\n██║     ██║██████╔╝███████"
  },
  {
    "path": "ciphey/common.py",
    "chars": 655,
    "preview": "\"\"\"Some useful adapters\"\"\"\nfrom typing import Any\n\n\ndef id_lambda(value: Any):\n    \"\"\"\n    A function used in dynamic cl"
  },
  {
    "path": "ciphey/iface/__init__.py",
    "chars": 417,
    "preview": "from ._config import Config\n\nfrom ._modules import (\n    Checker,\n    Cracker,\n    CrackInfo,\n    CrackResult,\n    Decod"
  },
  {
    "path": "ciphey/iface/_config.py",
    "chars": 7273,
    "preview": "import datetime\nimport os\nimport pydoc\nfrom typing import Any, Callable, Dict, List, Optional, Type, Union\n\nimport appdi"
  },
  {
    "path": "ciphey/iface/_fwd.py",
    "chars": 36,
    "preview": "registry = None\nconfig = type(None)\n"
  },
  {
    "path": "ciphey/iface/_modules.py",
    "chars": 11432,
    "preview": "from abc import ABC, abstractmethod\nfrom typing import Any, Dict, Generic, List, NamedTuple, Optional, Set, Type, TypeVa"
  },
  {
    "path": "ciphey/iface/_registry.py",
    "chars": 6237,
    "preview": "from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union\n\ntry:\n    from typing import get_args, get_origin\n"
  },
  {
    "path": "ciphey/mathsHelper.py",
    "chars": 7055,
    "preview": "\"\"\"\r\n ██████╗██╗██████╗ ██╗  ██╗███████╗██╗   ██╗\r\n██╔════╝██║██╔══██╗██║  ██║██╔════╝╚██╗ ██╔╝\r\n██║     ██║██████╔╝████"
  },
  {
    "path": "codecov.yml",
    "chars": 417,
    "preview": "codecov:\n  require_ci_to_pass: yes\n\ncoverage:\n  precision: 2\n  round: down\n  range: \"40...50\"\n  status:\n    patch: no\n  "
  },
  {
    "path": "license",
    "chars": 1055,
    "preview": "Copyright 2020 Brandon Skerritt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this so"
  },
  {
    "path": "noxfile.py",
    "chars": 2003,
    "preview": "\"\"\"\nThe file for Nox\n\"\"\"\nfrom typing import Any\n\nimport nox\nfrom nox.sessions import Session\n\nlocations = \"ciphey/\", \"te"
  },
  {
    "path": "pyproject.toml",
    "chars": 1003,
    "preview": "[tool.poetry]\nname = \"ciphey\"\nversion = \"5.14.1\"\ndescription = \"Automated Decryption Tool\"\nauthors = [\"Brandon <brandon@"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/brandon_interface.md",
    "chars": 14174,
    "preview": "\nIf I'm reading this correctly:\n> I would suggest a simple lower bound test: we pass if we get more than 25%,and fail if"
  },
  {
    "path": "tests/cli.py",
    "chars": 158,
    "preview": "import subprocess\nfrom sys import exit\n\nresult = subprocess.check_output([\"ciphey\", \"-q\", \"-t 'hello'\"])\n\nif \"hello\" in "
  },
  {
    "path": "tests/dict.py",
    "chars": 2702,
    "preview": "import unittest\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.basemods.Checkers.brandon import Brand"
  },
  {
    "path": "tests/enciphey.py",
    "chars": 5840,
    "preview": "import base64\nimport binascii\nimport random\nimport re\nimport string\n\nimport base58\nimport base62\nimport cipheycore\nimpor"
  },
  {
    "path": "tests/generate_tests.py",
    "chars": 2766,
    "preview": "\"\"\"\nCreate a class that can generate encryptions that ciphey can decrypt\nThis class takes a random string from a large c"
  },
  {
    "path": "tests/integration.py",
    "chars": 5651,
    "preview": "import unittest\n\nimport logging\nfrom rich.logging import RichHandler\n\nfrom ciphey.LanguageChecker import LanguageChecker"
  },
  {
    "path": "tests/lukas.py",
    "chars": 3075,
    "preview": "import random\n\nimport cipheydists\n\n\nclass galactic_encode:\n    \"\"\"\n    (Attempts to) encode an input string with the Sta"
  },
  {
    "path": "tests/speed_test.archive",
    "chars": 14477,
    "preview": "\"\"\"\nTL;DR\n\nTested over 20,000 times\n\nMaximum sentence size is 15 sentences\n1/2 chance of getting 'gibberish' (encrypted "
  },
  {
    "path": "tests/test_advanced_ciphers.py",
    "chars": 3874,
    "preview": "import pytest\r\nfrom click.testing import CliRunner\r\nimport mock \r\nimport re\r\n\r\nfrom ciphey import decrypt\r\nfrom ciphey.i"
  },
  {
    "path": "tests/test_click.py",
    "chars": 904,
    "preview": "from click.testing import CliRunner\r\nfrom ciphey.ciphey import main\r\nfrom ciphey.basemods.Checkers import human\r\nimport "
  },
  {
    "path": "tests/test_click_printing.py",
    "chars": 1780,
    "preview": "from click.testing import CliRunner\r\nfrom ciphey.ciphey import main\r\nfrom ciphey.basemods.Checkers import human\r\nimport "
  },
  {
    "path": "tests/test_main.py",
    "chars": 19877,
    "preview": "import pytest\n\nfrom ciphey import decrypt\nfrom ciphey.iface import Config\n\nanswer_str = \"Hello my name is bee and I like"
  },
  {
    "path": "tests/test_quick.py",
    "chars": 1408,
    "preview": "import pytest\r\n\r\nfrom ciphey import decrypt\r\nfrom ciphey.iface import Config\r\nfrom click.testing import CliRunner\r\nfrom "
  },
  {
    "path": "tests/test_regex.py",
    "chars": 667,
    "preview": "import pytest\r\n\r\nfrom ciphey import decrypt\r\nfrom ciphey.iface import Config\r\n\r\n\r\ndef test_regex_ip():\r\n    res = decryp"
  },
  {
    "path": "tools/freq_analysis.py",
    "chars": 185,
    "preview": "import json\nimport sys\n\nimport cipheycore\n\ndata = sys.stdin.read()\n\nanalysis = cipheycore.analyse_string(data)\n\nprint(js"
  },
  {
    "path": "translations/de/CODE_OF_CONDUCT.md",
    "chars": 4821,
    "preview": "<p align=\"center\">\nÜbersetzungen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDU"
  },
  {
    "path": "translations/de/CONTRIBUTING.md",
    "chars": 5107,
    "preview": "<p align=\"center\">\nÜbersetzungen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING."
  },
  {
    "path": "translations/de/README.md",
    "chars": 15374,
    "preview": "<p align=\"center\">\nÜbersetzungen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 "
  },
  {
    "path": "translations/fr/README.md",
    "chars": 20315,
    "preview": "<p align=\"center\">\nTraductions <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE"
  },
  {
    "path": "translations/hu/CODE_OF_CONDUCT.md",
    "chars": 4345,
    "preview": "<p align=\"center\">\nFordítások <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT."
  },
  {
    "path": "translations/hu/CONTRIBUTING.md",
    "chars": 3936,
    "preview": "<p align=\"center\">\nFordítások <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>"
  },
  {
    "path": "translations/hu/README.md",
    "chars": 19146,
    "preview": "<p align=\"center\">\nFordítások <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE "
  },
  {
    "path": "translations/id/CODE_OF_CONDUCT.md",
    "chars": 4334,
    "preview": "<p align=\"center\">\nTerjemahan <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT."
  },
  {
    "path": "translations/id/CONTRIBUTING.md",
    "chars": 4248,
    "preview": "<p align=\"center\">\nTerjemahan <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>"
  },
  {
    "path": "translations/id/README.md",
    "chars": 14030,
    "preview": "<p align=\"center\">\n<p align=\"center\">\nTerjemahan <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/"
  },
  {
    "path": "translations/it/CODE_OF_CONDUCT.md",
    "chars": 4901,
    "preview": "<p align=\"center\">\nTraduzioni <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT."
  },
  {
    "path": "translations/it/CONTRIBUTING.md",
    "chars": 4234,
    "preview": "<p align=\"center\">\nTraduzioni <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>"
  },
  {
    "path": "translations/it/README.md",
    "chars": 21909,
    "preview": "<p align=\"center\">\nTraduzioni <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE "
  },
  {
    "path": "translations/nl/CODE_OF_CONDUCT.md",
    "chars": 4540,
    "preview": "<p align=\"center\">\nVertalingen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT"
  },
  {
    "path": "translations/nl/CONTRIBUTING.md",
    "chars": 4188,
    "preview": "<p align=\"center\">\nVertalingen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md"
  },
  {
    "path": "translations/nl/README.md",
    "chars": 19925,
    "preview": "<p align=\"center\">\nVertalingen <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE"
  },
  {
    "path": "translations/pt-br/CODE_OF_CONDUCT.md",
    "chars": 4380,
    "preview": "<p align=\"center\">\nTraduções <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT.m"
  },
  {
    "path": "translations/pt-br/CONTRIBUTING.md",
    "chars": 4125,
    "preview": "<p align=\"center\">\nTraduções <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>🇩"
  },
  {
    "path": "translations/pt-br/README.md",
    "chars": 19659,
    "preview": "<p align=\"center\">\nTraduções <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE  "
  },
  {
    "path": "translations/ru/CODE_OF_CONDUCT.md",
    "chars": 4524,
    "preview": "<p align=\"center\">\nTranslations <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUC"
  },
  {
    "path": "translations/ru/CONTRIBUTING.md",
    "chars": 4119,
    "preview": "<p align=\"center\">\nTranslations <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.m"
  },
  {
    "path": "translations/ru/README.md",
    "chars": 20675,
    "preview": "<!-- comunity -->\n<!-- [markdownlint-enable](https://github.com/AABur) -->\n\n<p align=\"center\">\n<a href=https://github.co"
  },
  {
    "path": "translations/th/CODE_OF_CONDUCT.md",
    "chars": 3997,
    "preview": "<p align=\"center\">\nการแปล <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE   </"
  },
  {
    "path": "translations/th/CONTRIBUTING.md",
    "chars": 3556,
    "preview": "<p align=\"center\">\nการแปล <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE   </"
  },
  {
    "path": "translations/th/README.md",
    "chars": 24299,
    "preview": "<p align=\"center\">\nการแปล <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE   </"
  },
  {
    "path": "translations/zh/CODE_OF_CONDUCT.md",
    "chars": 2024,
    "preview": "<p align=\"center\">\n翻译 <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CODE_OF_CONDUCT.md>🇩🇪 DE"
  },
  {
    "path": "translations/zh/CONTRIBUTING.md",
    "chars": 2176,
    "preview": "<p align=\"center\">\n翻译 <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/CONTRIBUTING.md>🇩🇪 DE   "
  },
  {
    "path": "translations/zh/README.md",
    "chars": 17246,
    "preview": "<p align=\"center\">\n翻译 <br>\n<a href=https://github.com/Ciphey/Ciphey/tree/master/translations/de/README.md>🇩🇪 DE   </a>\n<"
  }
]

About this extraction

This page contains the full source code of the bee-san/Ciphey GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 144 files (581.8 KB), approximately 166.0k tokens, and a symbol index with 632 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!