pdf-to-markdown-cli 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docs_to_md/__init__.py +0 -0
- docs_to_md/__main__.py +5 -0
- docs_to_md/api/__init__.py +0 -0
- docs_to_md/api/client.py +218 -0
- docs_to_md/api/models.py +66 -0
- docs_to_md/config/__init__.py +0 -0
- docs_to_md/config/cli.py +86 -0
- docs_to_md/config/settings.py +108 -0
- docs_to_md/core/__init__.py +0 -0
- docs_to_md/core/processor.py +229 -0
- docs_to_md/core/result_handler.py +496 -0
- docs_to_md/main.py +55 -0
- docs_to_md/pdf/__init__.py +0 -0
- docs_to_md/pdf/splitter.py +199 -0
- docs_to_md/storage/__init__.py +0 -0
- docs_to_md/storage/cache.py +125 -0
- docs_to_md/storage/models.py +85 -0
- docs_to_md/utils/__init__.py +0 -0
- docs_to_md/utils/exceptions.py +33 -0
- docs_to_md/utils/file_utils.py +189 -0
- docs_to_md/utils/logging.py +134 -0
- pdf_to_markdown_cli-0.2.0.dist-info/METADATA +179 -0
- pdf_to_markdown_cli-0.2.0.dist-info/RECORD +27 -0
- pdf_to_markdown_cli-0.2.0.dist-info/WHEEL +5 -0
- pdf_to_markdown_cli-0.2.0.dist-info/entry_points.txt +2 -0
- pdf_to_markdown_cli-0.2.0.dist-info/licenses/LICENSE +21 -0
- pdf_to_markdown_cli-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
# Keep tqdm import at top level
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
def setup_logging(level: int = logging.INFO, log_file: Optional[str] = None) -> logging.Logger:
|
|
9
|
+
"""
|
|
10
|
+
Set up standardized logging configuration.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
level: Logging level (default: INFO)
|
|
14
|
+
log_file: Optional file path to write logs to
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Logger instance for the application.
|
|
18
|
+
"""
|
|
19
|
+
# Create formatter
|
|
20
|
+
formatter = logging.Formatter(
|
|
21
|
+
fmt="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
|
22
|
+
datefmt="%Y-%m-%d %H:%M:%S"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Create handlers
|
|
26
|
+
handlers = []
|
|
27
|
+
|
|
28
|
+
# Console handler (using stderr for better tqdm compatibility)
|
|
29
|
+
console_handler = logging.StreamHandler(stream=sys.stderr)
|
|
30
|
+
console_handler.setFormatter(formatter)
|
|
31
|
+
handlers.append(console_handler)
|
|
32
|
+
|
|
33
|
+
# File handler if specified
|
|
34
|
+
if log_file:
|
|
35
|
+
file_handler = logging.FileHandler(log_file)
|
|
36
|
+
file_handler.setFormatter(formatter)
|
|
37
|
+
handlers.append(file_handler)
|
|
38
|
+
|
|
39
|
+
# Configure root logger
|
|
40
|
+
root_logger = logging.getLogger()
|
|
41
|
+
root_logger.setLevel(level)
|
|
42
|
+
|
|
43
|
+
# Remove existing handlers from root logger to avoid duplication
|
|
44
|
+
for handler in root_logger.handlers[:]:
|
|
45
|
+
root_logger.removeHandler(handler)
|
|
46
|
+
|
|
47
|
+
# Add our handlers to root logger
|
|
48
|
+
for handler in handlers:
|
|
49
|
+
root_logger.addHandler(handler)
|
|
50
|
+
|
|
51
|
+
# Silence noisy library loggers
|
|
52
|
+
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
|
53
|
+
logging.getLogger("backoff").setLevel(logging.WARNING)
|
|
54
|
+
|
|
55
|
+
# Get and return the application-specific logger
|
|
56
|
+
logger = logging.getLogger("docs_to_md") # Updated name
|
|
57
|
+
# Ensure the app logger also has the correct level if root is different
|
|
58
|
+
logger.setLevel(level)
|
|
59
|
+
return logger
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ProgressTracker:
|
|
63
|
+
"""
|
|
64
|
+
Manages progress tracking for long-running operations.
|
|
65
|
+
Uses tqdm for progress bars but abstracts its usage.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, total: int, description: str, unit: str = "item"):
|
|
69
|
+
"""
|
|
70
|
+
Initialize a progress tracker.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
total: Total number of items to process
|
|
74
|
+
description: Description of the progress (shown in the bar)
|
|
75
|
+
unit: Unit of items being processed
|
|
76
|
+
"""
|
|
77
|
+
self.pbar: Optional[tqdm] = None
|
|
78
|
+
self._has_tqdm: bool = False
|
|
79
|
+
self.description = description # For fallback
|
|
80
|
+
self.total = total # For fallback
|
|
81
|
+
self.current = 0 # For fallback
|
|
82
|
+
self.logger = logging.getLogger("docs_to_md.progress") # Updated name
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
# Initialize tqdm here
|
|
86
|
+
self.pbar = tqdm(
|
|
87
|
+
total=total,
|
|
88
|
+
desc=description,
|
|
89
|
+
unit=unit,
|
|
90
|
+
file=sys.stderr, # Explicitly use stderr
|
|
91
|
+
leave=False
|
|
92
|
+
)
|
|
93
|
+
self._has_tqdm = True
|
|
94
|
+
except Exception as e: # Catching generic Exception is broad, but okay for try/except on import/init
|
|
95
|
+
self.logger.warning(f"Could not initialize tqdm: {e}. Falling back to log messages.")
|
|
96
|
+
self._has_tqdm = False
|
|
97
|
+
|
|
98
|
+
def __enter__(self):
|
|
99
|
+
# The pbar is already created in __init__ if possible
|
|
100
|
+
return self
|
|
101
|
+
|
|
102
|
+
def update(self, count: int = 1) -> None:
|
|
103
|
+
"""
|
|
104
|
+
Update progress count.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
count: Number of items to add to progress (default: 1)
|
|
108
|
+
"""
|
|
109
|
+
if self._has_tqdm and self.pbar:
|
|
110
|
+
self.pbar.update(count)
|
|
111
|
+
else:
|
|
112
|
+
self.current += count
|
|
113
|
+
# Log progress only periodically or based on some condition to avoid excessive logging
|
|
114
|
+
if self.current % 10 == 0 or self.current == self.total: # Example: log every 10 updates or on completion
|
|
115
|
+
self.logger.info(f"{self.description}: {self.current}/{self.total}")
|
|
116
|
+
|
|
117
|
+
def close(self) -> None:
|
|
118
|
+
"""Close the progress tracker and free resources."""
|
|
119
|
+
if self._has_tqdm and self.pbar:
|
|
120
|
+
self.pbar.close()
|
|
121
|
+
|
|
122
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
123
|
+
self.close()
|
|
124
|
+
|
|
125
|
+
# Example usage (for testing):
|
|
126
|
+
# if __name__ == "__main__":
|
|
127
|
+
# setup_logging()
|
|
128
|
+
# log = logging.getLogger("docs_to_md")
|
|
129
|
+
# log.info("Starting test")
|
|
130
|
+
# with ProgressTracker(10, "Testing Progress") as pt:
|
|
131
|
+
# for i in range(10):
|
|
132
|
+
# time.sleep(0.2)
|
|
133
|
+
# pt.update()
|
|
134
|
+
# log.info("Finished test")
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdf-to-markdown-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI tool to convert PDF files (and other documents) to markdown using the Marker API.
|
|
5
|
+
Home-page: https://github.com/SokolskyNikita/pdf-to-markdown-cli
|
|
6
|
+
Author: Nikita Sokolsky
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/SokolskyNikita/pdf-to-markdown-cli/issues
|
|
8
|
+
Keywords: pdf,markdown,converter,cli,document,marker,md
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Topic :: Text Processing
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: backoff>=2.0
|
|
24
|
+
Requires-Dist: diskcache>=5.0
|
|
25
|
+
Requires-Dist: filetype>=1.0
|
|
26
|
+
Requires-Dist: pikepdf>=8.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0
|
|
28
|
+
Requires-Dist: ratelimit>=2.0
|
|
29
|
+
Requires-Dist: requests>=2.0
|
|
30
|
+
Requires-Dist: tqdm>=4.0
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: project-url
|
|
39
|
+
Dynamic: requires-dist
|
|
40
|
+
Dynamic: requires-python
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# PDF to Markdown CLI (using Marker API)
|
|
44
|
+
|
|
45
|
+
Convert PDF files (and other documents) to markdown using the [Marker API](https://www.marker.io/) via a command-line tool.
|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
|
|
49
|
+
This package provides a convenient command-line interface (`pdf-to-md`) for converting PDF files (and other document formats like Word, EPUB, images, etc.) to markdown. It leverages the Marker API for high-quality PDF conversion and handles chunking, parallel processing, and result combination.
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- Convert PDFs, Word documents, PowerPoint files, spreadsheets, epub, HTML, and images to markdown
|
|
54
|
+
- Optionally use the Marker API for enhanced PDF conversion
|
|
55
|
+
- Handle large documents by splitting them into chunks
|
|
56
|
+
- Progress tracking for long-running operations
|
|
57
|
+
- Customizable OCR options
|
|
58
|
+
- Local caching of results
|
|
59
|
+
- Output in markdown, JSON, or HTML format
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
### From PyPI
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install pdf-to-markdown-cli
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### From source
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/SokolskyNikita/pdf-to-markdown-cli.git
|
|
73
|
+
cd pdf-to-markdown-cli
|
|
74
|
+
pip install -e .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
### Command-line interface
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Set your Marker API key
|
|
83
|
+
export MARKER_PDF_KEY=your_api_key_here
|
|
84
|
+
|
|
85
|
+
# Basic usage
|
|
86
|
+
pdf-to-md /path/to/file.pdf
|
|
87
|
+
|
|
88
|
+
# Process all files in a directory
|
|
89
|
+
pdf-to-md /path/to/directory
|
|
90
|
+
|
|
91
|
+
# Output in JSON format
|
|
92
|
+
pdf-to-md /path/to/file.pdf --json
|
|
93
|
+
|
|
94
|
+
# Use additional languages for OCR
|
|
95
|
+
pdf-to-md /path/to/file.pdf --langs "English,French,German"
|
|
96
|
+
|
|
97
|
+
# Use all Marker OCR enhancements
|
|
98
|
+
pdf-to-md /path/to/file.pdf --max
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### API
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# Internal module paths remain the same
|
|
105
|
+
from docs_to_md.config.settings import Config
|
|
106
|
+
from docs_to_md.core.processor import MarkerProcessor
|
|
107
|
+
|
|
108
|
+
# Create configuration
|
|
109
|
+
config = Config(
|
|
110
|
+
api_key="your_api_key_here",
|
|
111
|
+
input_path="/path/to/file.pdf",
|
|
112
|
+
output_format="markdown",
|
|
113
|
+
use_llm=True
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Create processor and run
|
|
117
|
+
processor = MarkerProcessor(config)
|
|
118
|
+
processor.process()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Command-line Options
|
|
122
|
+
|
|
123
|
+
- `input`: Input file or directory path
|
|
124
|
+
- `--json`: Output in JSON format (default is markdown)
|
|
125
|
+
- `--langs`: Comma-separated OCR languages (default: "English")
|
|
126
|
+
- `--llm`: Use LLM for enhanced processing
|
|
127
|
+
- `--strip`: Redo OCR processing
|
|
128
|
+
- `--noimg`: Disable image extraction
|
|
129
|
+
- `--force`: Force OCR on all pages
|
|
130
|
+
- `--pages`: Add page delimiters
|
|
131
|
+
- `--max`: Enable all OCR enhancements (equivalent to --llm --strip --force)
|
|
132
|
+
- `--max-pages`: Maximum number of pages to process from the start of the file
|
|
133
|
+
- `--no-chunk`: Disable PDF chunking
|
|
134
|
+
- `--chunk-size`: Set PDF chunk size in pages (default: 25)
|
|
135
|
+
- `--output-dir`: Output directory (default: "converted")
|
|
136
|
+
- `--cache-dir`: Cache directory (default: ".marker_cache")
|
|
137
|
+
|
|
138
|
+
## Project Structure
|
|
139
|
+
|
|
140
|
+
The package is organized as follows:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
pdf-to-markdown-cli/ (Project Root)
|
|
144
|
+
├── docs_to_md/ (Python Package Source)
|
|
145
|
+
│ ├── api/
|
|
146
|
+
│ ├── config/
|
|
147
|
+
│ ├── core/
|
|
148
|
+
│ ├── pdf/
|
|
149
|
+
│ ├── storage/
|
|
150
|
+
│ └── utils/
|
|
151
|
+
├── setup.py
|
|
152
|
+
├── README.md
|
|
153
|
+
└── ... (other config files)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Requirements
|
|
157
|
+
|
|
158
|
+
- Python 3.10 or higher
|
|
159
|
+
- Runtime dependencies are listed in `setup.py` and automatically installed via pip.
|
|
160
|
+
- The `requirements.txt` file lists exact versions used for development and testing, and can be used to set up a development environment: `pip install -r requirements.txt`
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
To run the code directly from the source tree without installation:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Using the installed entry point (requires editable install):
|
|
168
|
+
# pip install -e .
|
|
169
|
+
# pdf-to-md /path/to/file.pdf
|
|
170
|
+
|
|
171
|
+
# Or running the module directly:
|
|
172
|
+
python -m docs_to_md /path/to/file.pdf
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For regular use after installation, use the `pdf-to-md` command.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
docs_to_md/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
docs_to_md/__main__.py,sha256=ebTiYZ1owy2lbPJNsCEKfGGAvr91uFJeeoZt-7tI0-k,83
|
|
3
|
+
docs_to_md/main.py,sha256=P8m9mYk4sHAimTZX2vhGKJORBMyDJQHqih0YAGyc-hg,1358
|
|
4
|
+
docs_to_md/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
docs_to_md/api/client.py,sha256=YSHbkc6JKQG-RzR0R6mfuxpSlIh3JrTmVm-hhQHxCiM,7945
|
|
6
|
+
docs_to_md/api/models.py,sha256=cblbgWP4PXS3rtGkY_2FKD2A__imdfDN5Hlx93euBOw,2258
|
|
7
|
+
docs_to_md/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
docs_to_md/config/cli.py,sha256=CQsyXrlwFzGdYvLUZJCTxHQOsCWEEAumWyZ1oVUsqGo,3267
|
|
9
|
+
docs_to_md/config/settings.py,sha256=9MkZqE8AAeNulWj4Stx6EPZHbhGWE5sMuV0eg9djfzA,3967
|
|
10
|
+
docs_to_md/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
docs_to_md/core/processor.py,sha256=nHekhyquNfJ-2QLxQH5j5ybGOFVJDujkQvavPt9hkRc,8649
|
|
12
|
+
docs_to_md/core/result_handler.py,sha256=a333CyvxSHbgZrJOPE4uxcIYswNZyr9rETMiCpjg_nA,18449
|
|
13
|
+
docs_to_md/pdf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
docs_to_md/pdf/splitter.py,sha256=ZSzyAcWx0hmyEbK1uCEzb5iTRqg8AB46NDPVe0PUhcA,5926
|
|
15
|
+
docs_to_md/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
docs_to_md/storage/cache.py,sha256=ZRntNXieRrFKyD6YE_8iZuzI8WriHzJoV3cKDKKxLFU,3817
|
|
17
|
+
docs_to_md/storage/models.py,sha256=KKKhJtkNvOlS-snksjL2KaggSqhrP67bXoPc1li8KXE,2841
|
|
18
|
+
docs_to_md/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
docs_to_md/utils/exceptions.py,sha256=ljStvAU6wY0G-lbJENgwp_JUq5wQqCOGOfQYrchqCAw,757
|
|
20
|
+
docs_to_md/utils/file_utils.py,sha256=3oMDAol8LF5ExZtaa8BHNtDkNwKY_aqKbz4gx018ZLg,6699
|
|
21
|
+
docs_to_md/utils/logging.py,sha256=KD3V-4XqQ18ZANEj8-DvAvY8kbgnjJPPwpQEWz1Ny7w,4496
|
|
22
|
+
pdf_to_markdown_cli-0.2.0.dist-info/licenses/LICENSE,sha256=TvzNGSILmRdjt79Z-5m7QYS8dOY2hoszcVo_KxZRA5s,1071
|
|
23
|
+
pdf_to_markdown_cli-0.2.0.dist-info/METADATA,sha256=NRTVoyaGT3voVDNG-UbjbCzhQOHy4pCnN34tXuUMhXQ,5220
|
|
24
|
+
pdf_to_markdown_cli-0.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
25
|
+
pdf_to_markdown_cli-0.2.0.dist-info/entry_points.txt,sha256=gL4qvIudGRvzVrAZWqpyspqDVEtJbFpGuHiwj7_N_Ds,51
|
|
26
|
+
pdf_to_markdown_cli-0.2.0.dist-info/top_level.txt,sha256=6P0VeRWDqZ8Ckk8xooPcwNAPPgep5yVEYmmcI3A9C2M,11
|
|
27
|
+
pdf_to_markdown_cli-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 SokolskyNikita
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
docs_to_md
|