runongpu 0.1.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.
runongpu/cli.py ADDED
@@ -0,0 +1,107 @@
1
+ # Builds the command-line interface for RunOnGPU.
2
+ import typer
3
+
4
+ # Prints styled terminal output for a better CLI experience.
5
+ from rich.console import Console
6
+
7
+ # Project helpers for saving local config, creating runongpu.txt, and loading user settings.
8
+ from runongpu.config import create_runongpu_template_file, get_folder_name_from_repo_url, save_notebook_url, save_repo_url, load_config
9
+ from runongpu.colab import open_colab
10
+ from runongpu.parser import parse_config
11
+
12
+
13
+ app = typer.Typer()
14
+ console = Console()
15
+
16
+
17
+ @app.command()
18
+ def doctor():
19
+ # Verifies that the user's local RunOnGPU setup has the required pieces installed.
20
+ console.print("[bold cyan]Checking RunOnGPU setup...[/bold cyan]")
21
+
22
+ console.print("[green]✓ CLI is running[/green]")
23
+ console.print("[green]✓ Typer is installed[/green]")
24
+ console.print("[green]✓ Rich is installed[/green]")
25
+
26
+ saved_config = load_config()
27
+
28
+ if saved_config is None:
29
+ console.print("[yellow]⚠ No repo URL saved yet[/yellow]")
30
+ console.print("[yellow]Run: runongpu init[/yellow]")
31
+ else:
32
+ console.print("[green]✓ Repo URL is saved[/green]")
33
+ console.print(f"[green] Repo URL: {saved_config["repo_url"]}")
34
+
35
+ try:
36
+ import playwright
37
+ console.print("[green]✓ Playwright is installed[/green]")
38
+ except ImportError:
39
+ console.print("[red]✗ Playwright is not installed[/red]")
40
+ console.print("[yellow]Run: pip install playwright[/yellow]")
41
+
42
+
43
+ @app.command()
44
+ def init():
45
+ # Store the GitHub repo that RunOnGPU should clone inside Colab.
46
+ repo_url = typer.prompt("Enter your Github repo URL")
47
+
48
+ console.print("[yellow]Deriving folder name[/yellow]")
49
+ folder_name = get_folder_name_from_repo_url(repo_url)
50
+ console.print("[green]Successfully derived folder name[/green]")
51
+
52
+ save_repo_url(repo_url, folder_name)
53
+
54
+ # Create a starter runongpu.txt so users know where to put setup/build/test/run commands.
55
+ create_runongpu_template_file()
56
+
57
+ console.print("[green]✓ Github repo URL saved. [/green]")
58
+
59
+
60
+ @app.command()
61
+ def config():
62
+ # Show the saved local settings without opening Colab.
63
+ saved_config = load_config()
64
+
65
+ if saved_config is None:
66
+ console.print("[yellow]No repo url found. Run `runongpu init` first.[/yellow]")
67
+ return
68
+
69
+ console.print("[bold cyan]Saved RunOnGPU config:[/bold cyan]")
70
+ console.print(f"GitHub repo URL: [green]{saved_config['repo_url']}[/green]")
71
+
72
+ notebook_url = saved_config.get("notebook_url", "")
73
+
74
+ if notebook_url:
75
+ console.print(f"Colab notebook URL: [green]{notebook_url}[/green]")
76
+ else:
77
+ console.print("Colab notebook URL: [yellow]Not saved yet[/yellow]")
78
+
79
+
80
+ @app.command()
81
+ def run():
82
+ # Main workflow: parse project commands, open Colab, write the notebook cell, and save the notebook URL.
83
+ saved_config = load_config()
84
+
85
+ if saved_config is None:
86
+ console.print("[red]No repo URL saved. Run `runongpu init` first.[/red]")
87
+ return
88
+
89
+ try:
90
+ console.print("[yellow]Parsing runongpu.txt. [/yellow]")
91
+ project_config = parse_config()
92
+ console.print("[green] Successfully parsed through runongpu.txt")
93
+ except ValueError as error:
94
+ console.print(f"[red] runongpu.txt error: [/red]\n {error}")
95
+ return
96
+
97
+ notebook_url = saved_config.get("notebook_url", "")
98
+
99
+ console.print("[bold cyan]Starting RunOnGPU...[/bold cyan]")
100
+ current_notebook_url = open_colab(notebook_url, project_config)
101
+
102
+ # Save the copied Colab notebook so future runs reuse it instead of creating another copy.
103
+ save_notebook_url(current_notebook_url)
104
+
105
+
106
+ if __name__ == "__main__":
107
+ app()
runongpu/colab.py ADDED
@@ -0,0 +1,199 @@
1
+ import os
2
+ import subprocess
3
+ import time
4
+ from pathlib import Path
5
+ from urllib.error import URLError
6
+ from urllib.request import urlopen
7
+
8
+ from playwright.sync_api import sync_playwright
9
+
10
+ from runongpu.config import load_config
11
+
12
+ from rich.console import Console
13
+
14
+ console = Console()
15
+
16
+ # Path to the real Chrome executable on Windows.
17
+ # RunOnGPU uses real Chrome because Colab/Google login is more reliable there
18
+ # than in Playwright's bundled browser.
19
+ CHROME_EXE = (
20
+ Path(os.environ["PROGRAMFILES"])
21
+ / "Google"
22
+ / "Chrome"
23
+ / "Application"
24
+ / "chrome.exe"
25
+ )
26
+
27
+ # Dedicated Chrome profile for RunOnGPU.
28
+ # This keeps Colab login/session data persistent without touching the user's
29
+ # everyday Chrome profile.
30
+ RUNONGPU_PROFILE_DIR = Path.home() / ".runongpu" / "chrome-profile"
31
+
32
+ # Local Chrome DevTools Protocol port.
33
+ # Playwright connects to this port to control the real Chrome window.
34
+ DEBUG_PORT = 9222
35
+
36
+ # Shared starter notebook used only when the user does not already have a saved
37
+ # RunOnGPU notebook URL.
38
+ TEMPLATE_URL = "https://colab.research.google.com/drive/1pB8iVjR4-tPVSEBFjY8ow6N_F34bcMwi?usp=sharing"
39
+
40
+
41
+ def wait_for_debug_port(timeout_seconds: int = 15) -> None:
42
+ """Wait until Chrome is ready for Playwright to connect."""
43
+ start_time = time.time()
44
+
45
+ while time.time() - start_time < timeout_seconds:
46
+ try:
47
+ # Chrome exposes this local endpoint after remote debugging starts.
48
+ with urlopen(f"http://127.0.0.1:{DEBUG_PORT}/json/version", timeout=1):
49
+ return
50
+ except URLError:
51
+ # Chrome can take a moment to launch, so retry briefly instead of failing immediately.
52
+ time.sleep(0.5)
53
+
54
+
55
+ raise RuntimeError(
56
+ f"Chrome did not open remote debugging port {DEBUG_PORT}. "
57
+ "Close Chrome and try again, or use a different debug port."
58
+ )
59
+
60
+
61
+ def open_colab(notebook_url: str = "", project_config: dict | None = None) -> str:
62
+ """Open a saved Colab notebook, or copy the template notebook on first run."""
63
+
64
+ target_url = notebook_url or TEMPLATE_URL
65
+
66
+ # Launch real Chrome with remote debugging enabled so Playwright can attach.
67
+ # The custom profile lets users sign into Colab once and reuse that session.
68
+ subprocess.Popen([
69
+ str(CHROME_EXE),
70
+ f"--remote-debugging-port={DEBUG_PORT}",
71
+ f"--user-data-dir={RUNONGPU_PROFILE_DIR}",
72
+ "--no-first-run",
73
+ "--no-default-browser-check",
74
+ target_url,
75
+ ])
76
+
77
+ # Avoid connecting before Chrome has opened its debugging endpoint.
78
+ wait_for_debug_port()
79
+
80
+ with sync_playwright() as playwright:
81
+ # Attach to the already-open real Chrome window instead of launching a new browser.
82
+ browser = playwright.chromium.connect_over_cdp(
83
+ f"http://127.0.0.1:{DEBUG_PORT}"
84
+ )
85
+
86
+ # Use the active browser context and newest tab opened by RunOnGPU.
87
+ context = browser.contexts[0]
88
+ page = context.pages[-1]
89
+
90
+ if not notebook_url:
91
+ while True:
92
+ # Saving a copy usually opens a new Colab tab. expect_page captures
93
+ # that tab directly instead of guessing with context.pages[-1].
94
+ with context.expect_page() as new_page_info:
95
+ page.get_by_role("button", name="File", exact=True).click()
96
+ page.get_by_text("Save a copy in Drive").click()
97
+
98
+ # Switch automation to the copied notebook tab.
99
+ page = new_page_info.value
100
+ page.wait_for_load_state("domcontentloaded")
101
+
102
+ copied_successfully = (
103
+ page.url != target_url
104
+ and "accounts.google.com" not in page.url
105
+ )
106
+
107
+ if copied_successfully:
108
+ break
109
+
110
+ input("Please sign into Colab, then press Enter to try again. If already signed in, press enter...")
111
+
112
+ current_url = page.url
113
+
114
+ if project_config is None:
115
+ raise RuntimeError("project_config was not passed into open_colab().")
116
+
117
+ # project_config contains the parsed setup/build/test/run commands from runongpu.txt.
118
+ console.print(f"[cyan]project_config:[/cyan] {project_config}")
119
+ console.print("[cyan]Writing RunOnGPU cell...[/cyan]")
120
+ write_runongpu_cell(page, project_config)
121
+
122
+ console.print("[green]✓ RunOnGPU cell written[/green]")
123
+ set_t4_gpu_and_run_all(page)
124
+
125
+ input("Colab is open. Press Enter when done...")
126
+
127
+ browser.close()
128
+
129
+ return current_url
130
+
131
+
132
+ def write_runongpu_cell(page, project_config: dict):
133
+ saved_config = load_config()
134
+
135
+ # Close popups such as Gemini/Colab assistant before selecting the target cell.
136
+ page.keyboard.press("Escape")
137
+ page.wait_for_timeout(1000)
138
+
139
+ # Target a known marker in the template instead of relying on the first visible editor.
140
+ # This avoids accidentally pasting into Gemini or another popup editor.
141
+ target_cell = page.get_by_text("# Paste your code here:", exact=False).first
142
+ target_cell.click()
143
+
144
+ # Preserve the intended execution order from runongpu.txt:
145
+ # install dependencies, build the project, run tests, then run the program.
146
+ all_commands = (
147
+ project_config["setup"]
148
+ + project_config["build"]
149
+ + project_config["test"]
150
+ + project_config["run"]
151
+ )
152
+
153
+ # Colab shell commands use !, so each parsed command becomes a notebook shell line.
154
+ command_lines = "\n".join(f"!{command}" for command in all_commands)
155
+
156
+ page.keyboard.press("Control+A")
157
+
158
+ folder_name = saved_config["folder_name"]
159
+ repo_url = saved_config["repo_url"]
160
+
161
+ code = f"""
162
+ # Paste your code here:
163
+ folder_name = "{folder_name}"
164
+ github_repo_url = "{repo_url}"
165
+ !rm -rf {folder_name}
166
+ !git clone {{github_repo_url}}
167
+ %cd {{folder_name}}
168
+ {command_lines}
169
+ """
170
+
171
+ # Clipboard paste is faster and more reliable than typing long generated cells.
172
+ page.evaluate("text => navigator.clipboard.writeText(text)", code)
173
+ page.keyboard.press("Control+V")
174
+
175
+
176
+ def set_t4_gpu_and_run_all(page) -> None:
177
+ # Open Colab runtime settings so the notebook uses a GPU runtime.
178
+ console.print("[cyan]Opening Runtime menu...[/cyan]")
179
+ page.get_by_role("button", name="Runtime", exact=True).click()
180
+
181
+ console.print("[cyan]Opening Change runtime type...[/cyan]")
182
+ page.get_by_role("menuitem", name="Change runtime type", exact=True).click()
183
+
184
+ # Select the free T4 GPU option available in Colab.
185
+ console.print("[cyan]Selecting T4 GPU...[/cyan]")
186
+ page.get_by_role("radio", name="T4 GPU").click()
187
+
188
+ console.print("[cyan]Saving runtime settings...[/cyan]")
189
+ page.get_by_role("button", name="Save").click()
190
+
191
+ # Give Colab time to close the runtime dialog before sending keyboard shortcuts.
192
+ console.print("[cyan]Waiting for runtime dialog to close...[/cyan]")
193
+ page.wait_for_timeout(3000)
194
+ page.keyboard.press("Escape")
195
+
196
+ # Start the notebook after the runtime is configured.
197
+ console.print("[cyan]Running all cells...[/cyan]")
198
+ page.keyboard.press("Control+F9")
199
+ console.print("[green]✓ Runtime set and cells started[/green]")
runongpu/config.py ADDED
@@ -0,0 +1,111 @@
1
+ # Configuration helpers for RunOnGPU.
2
+ # This file manages small local settings that should persist between CLI runs,
3
+ # such as the GitHub repository URL and the copied Colab notebook URL.
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from rich.console import Console
8
+
9
+ console = Console()
10
+
11
+ # Store RunOnGPU settings in the user's home directory instead of the project repo.
12
+ # This keeps personal/local state out of Git.
13
+ CONFIG_DIR = Path.home() / ".runongpu"
14
+
15
+ CONFIG_FILE = CONFIG_DIR / "config.json"
16
+
17
+
18
+ def save_repo_url(repo_url: str, folder_name: str) -> None:
19
+ CONFIG_DIR.mkdir(exist_ok=True)
20
+ config = {
21
+ "repo_url": repo_url,
22
+ "notebook_url": "",
23
+ "folder_name": folder_name
24
+ }
25
+
26
+ # Persist the selected project so future `runongpu run` calls know what to clone.
27
+ with open(CONFIG_FILE, "w", encoding="utf-8") as file:
28
+ json.dump(config, file, indent=4)
29
+
30
+
31
+ def load_config() -> dict | None:
32
+ # Return None when the user has not run `runongpu init` yet.
33
+ if not CONFIG_FILE.exists():
34
+ return None
35
+
36
+ # Convert the saved JSON config back into a Python dictionary.
37
+ with open(CONFIG_FILE, "r", encoding="utf-8") as file:
38
+ return json.load(file)
39
+
40
+
41
+ def save_notebook_url(notebook_url: str) -> None:
42
+ # Keep the copied Colab notebook URL so RunOnGPU reuses it instead of
43
+ # creating a new notebook copy every time.
44
+ config = load_config()
45
+
46
+ if config is None:
47
+ config = {}
48
+
49
+ config["notebook_url"] = notebook_url
50
+
51
+ with open(CONFIG_FILE, "w", encoding="utf-8") as file:
52
+ json.dump(config, file, indent=4)
53
+
54
+
55
+ def create_runongpu_template_file() -> None:
56
+ # Create a starter runongpu.txt in the current project folder.
57
+ # The file documents the command sections that RunOnGPU later parses.
58
+ txt_path = Path("runongpu.txt")
59
+
60
+ if not txt_path.exists():
61
+
62
+ txt_path.write_text(
63
+ """# RunOnGPU Configuration
64
+ #
65
+ # Add one command per line under each section.
66
+ # Empty sections are allowed.
67
+ #
68
+ # Example Python project:
69
+ #
70
+ # [setup]
71
+ # pip install -r requirements.txt
72
+ #
73
+ # [run]
74
+ # python main.py
75
+ #
76
+ # Example CUDA project:
77
+ #
78
+ # [build]
79
+ # nvcc main.cu -o main
80
+ #
81
+ # [run]
82
+ # ./main
83
+ #
84
+ # Example CMake project:
85
+ #
86
+ # [build]
87
+ # cmake -S . -B build
88
+ # cmake --build build
89
+ #
90
+ # [run]
91
+ # ./build/my_program
92
+
93
+ [setup]
94
+
95
+ [build]
96
+
97
+ [test]
98
+
99
+ [run]
100
+ """,
101
+ encoding="utf-8",
102
+ )
103
+ console.print("[green]✓ Added runongpu.txt to the repo. [/green]")
104
+ else:
105
+ console.print("[yellow]runongpu.txt already exists. Good job! Proud of you! [/yellow]")
106
+
107
+
108
+ def get_folder_name_from_repo_url(repo_url: str) -> str:
109
+ # Git clones repositories into a folder named after the repo, so derive that
110
+ # folder name from the URL instead of asking the user to type it manually.
111
+ return repo_url.rstrip("/").split("/")[-1].replace(".git", "")
runongpu/parser.py ADDED
@@ -0,0 +1,46 @@
1
+ from pathlib import Path
2
+
3
+
4
+ def parse_config() -> dict:
5
+ # Each section maps to the list of commands RunOnGPU should run in Colab.
6
+ config = {
7
+ "setup": [],
8
+ "build": [],
9
+ "test": [],
10
+ "run": [],
11
+ }
12
+
13
+ current_section = None
14
+
15
+ # Path("runongpu.txt") looks for the file in the current terminal directory.
16
+ # Users should run RunOnGPU from the project folder that contains runongpu.txt.
17
+ txt_path = Path("runongpu.txt")
18
+
19
+ for line in txt_path.read_text(encoding="utf-8").splitlines():
20
+ line = line.strip()
21
+
22
+ # Ignore spacing and documentation inside runongpu.txt.
23
+ if not line:
24
+ continue
25
+
26
+ if line.startswith("#"):
27
+ continue
28
+
29
+ # Section headers decide where the following commands should be stored.
30
+ # Example: [build] makes current_section equal to "build".
31
+ if line.startswith("[") and line.endswith("]"):
32
+ section = line[1:-1].lower()
33
+
34
+ if section not in config:
35
+ raise ValueError(f"Unknown section: {section}")
36
+
37
+ current_section = section
38
+ continue
39
+
40
+ # Commands must appear under a valid section so RunOnGPU knows when to run them.
41
+ if current_section is None:
42
+ raise ValueError("Command found before any section header.")
43
+
44
+ config[current_section].append(line)
45
+
46
+ return config
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: runongpu
3
+ Version: 0.1.0
4
+ Summary: A CLI tool that runs GitHub projects on free cloud GPUs
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: typer
9
+ Requires-Dist: rich
10
+ Requires-Dist: playwright
11
+ Dynamic: license-file
12
+
13
+ # RunOnGPU
14
+
15
+ RunOnGPU is a CLI tool that helps you run GitHub projects on a GPU with minimal setup.
16
+
17
+ It is useful if you want to test CUDA, PyTorch, or other GPU code but do not have a local NVIDIA GPU.
18
+
19
+ ## Requirements
20
+
21
+ * Windows
22
+ * Python 3.10+
23
+ * Git
24
+ * Google Chrome
25
+ * Google account for Colab
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install runongpu
31
+ python -m playwright install
32
+
33
+ Check setup:
34
+
35
+ ```bash
36
+ runongpu doctor
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ Go to the project you want to run and initialize RunOnGPU:
42
+
43
+ ```bash
44
+ runongpu init
45
+ ```
46
+
47
+ Enter your GitHub repo URL when asked.
48
+
49
+ This creates a `runongpu.txt` file. Edit this file to tell RunOnGPU how to set up, build, test, and run your project.
50
+
51
+ Then run:
52
+
53
+ ```bash
54
+ runongpu run
55
+ ```
56
+
57
+ RunOnGPU will open Colab, copy the starter notebook, clone your repo, set the runtime to a T4 GPU, and run your commands.
58
+
59
+ ## runongpu.txt
60
+
61
+ `runongpu.txt` controls what happens inside Colab.
62
+
63
+ It has four sections:
64
+
65
+ ```text
66
+ [setup]
67
+ # install dependencies here
68
+
69
+ [build]
70
+ # compile or build the project here
71
+
72
+ [test]
73
+ # run tests here
74
+
75
+ [run]
76
+ # run the final program here
77
+ ```
78
+
79
+ Add one command per line.
80
+
81
+ ## Example: CUDA
82
+
83
+ If your repo has this structure:
84
+
85
+ ```text
86
+ my-cuda-project/
87
+ ├── main.cu
88
+ └── runongpu.txt
89
+ ```
90
+
91
+ Use:
92
+
93
+ ```text
94
+ [setup]
95
+
96
+ [build]
97
+ nvcc main.cu -o vector_add
98
+
99
+ [test]
100
+
101
+ [run]
102
+ ./vector_add
103
+ ```
104
+
105
+ ## Example: CUDA in a Subfolder
106
+
107
+ If your repo has this structure:
108
+
109
+ ```text
110
+ runongpu-examples/
111
+ ├── cuda/
112
+ │ └── vector-add/
113
+ │ └── main.cu
114
+ └── runongpu.txt
115
+ ```
116
+
117
+ Use:
118
+
119
+ ```text
120
+ [setup]
121
+
122
+ [build]
123
+ cd cuda/vector-add && nvcc main.cu -o vector_add
124
+
125
+ [test]
126
+
127
+ [run]
128
+ cd cuda/vector-add && ./vector_add
129
+ ```
130
+
131
+ ## Example: Python
132
+
133
+ ```text
134
+ [setup]
135
+ pip install -r requirements.txt
136
+
137
+ [build]
138
+
139
+ [test]
140
+ pytest
141
+
142
+ [run]
143
+ python main.py
144
+ ```
145
+
146
+ ## Example: CMake
147
+
148
+ ```text
149
+ [setup]
150
+
151
+ [build]
152
+ cmake -S . -B build
153
+ cmake --build build
154
+
155
+ [test]
156
+ ctest --test-dir build --output-on-failure
157
+
158
+ [run]
159
+ ./build/my_program
160
+ ```
161
+
162
+ ## Notes
163
+
164
+ On the first run, you may need to sign into Google Colab. RunOnGPU saves the copied notebook URL and reuses it on future runs.
165
+
166
+ Do not interact with the Colab window while RunOnGPU is setting it up.
167
+
168
+ ## Run Tests
169
+
170
+ ```bash
171
+ python -m pytest
172
+ ```
@@ -0,0 +1,10 @@
1
+ runongpu/cli.py,sha256=1qZ4YtnMsqhyUxaet21fbrOyr0l0XyOoKRrG2Azw6Uo,3777
2
+ runongpu/colab.py,sha256=xnEuOi5cTflpTrDIn07Z1cwrD_A90u0_2hX6hYwjM3s,7357
3
+ runongpu/config.py,sha256=GJMbfKEeJy4bYk7yXCH5nkcoCCiXTJ6E1LWahxb9lpc,2948
4
+ runongpu/parser.py,sha256=8lRiWjAdhxF881SSiZ7XoKDgH236GkinPV0WTbcvNLg,1439
5
+ runongpu-0.1.0.dist-info/licenses/LICENSE,sha256=NhuhsC4al9nqfixPdNMzo1fQYISuisuuOq_3p4844jA,1092
6
+ runongpu-0.1.0.dist-info/METADATA,sha256=9HdF8HLnnpRZvVOzP-bB-VucA1BxYM05RgqkgtCtK_0,2651
7
+ runongpu-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
8
+ runongpu-0.1.0.dist-info/entry_points.txt,sha256=MJdJNsR_cdsJlQPGnsTZXMgioq7WI4p1bpenVPANqEA,46
9
+ runongpu-0.1.0.dist-info/top_level.txt,sha256=733xt9x99LcPvPkvO6oHmaCaUbsJRbu09_1qKIk_gdk,9
10
+ runongpu-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ runongpu = runongpu.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MashrafeeAryan
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
+ runongpu