zrb 1.0.0a18__py3-none-any.whl → 1.0.0a21__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.
- zrb/__init__.py +5 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +1 -5
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +3 -9
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +44 -0
- zrb/config.py +17 -0
- zrb/input/any_input.py +4 -0
- zrb/input/base_input.py +4 -4
- zrb/input/bool_input.py +1 -1
- zrb/input/float_input.py +2 -2
- zrb/input/int_input.py +1 -1
- zrb/input/option_input.py +2 -2
- zrb/input/password_input.py +2 -2
- zrb/input/text_input.py +2 -2
- zrb/runner/cli.py +9 -34
- zrb/runner/common_util.py +31 -0
- zrb/runner/refresh-token.template.js +22 -0
- zrb/runner/web_app.py +211 -49
- zrb/runner/web_config.py +274 -0
- zrb/runner/web_controller/error_page/controller.py +27 -0
- zrb/runner/web_controller/error_page/view.html +34 -0
- zrb/runner/web_controller/group_info_page/controller.py +40 -0
- zrb/runner/web_controller/group_info_page/view.html +37 -0
- zrb/runner/web_controller/home_page/controller.py +13 -48
- zrb/runner/web_controller/home_page/view.html +30 -20
- zrb/runner/web_controller/login_page/controller.py +25 -0
- zrb/runner/web_controller/login_page/view.html +51 -0
- zrb/runner/web_controller/logout_page/controller.py +26 -0
- zrb/runner/web_controller/logout_page/view.html +41 -0
- zrb/runner/web_controller/{task_ui → session_page}/controller.py +35 -26
- zrb/runner/web_controller/{task_ui → session_page}/partial/input.html +1 -1
- zrb/runner/web_controller/session_page/view.html +92 -0
- zrb/runner/web_controller/static/common.css +11 -0
- zrb/runner/web_controller/static/login/event.js +33 -0
- zrb/runner/web_controller/static/logout/event.js +20 -0
- zrb/runner/web_controller/static/pico.min.css +1 -1
- zrb/runner/web_controller/static/session/common-util.js +63 -0
- zrb/runner/web_controller/static/session/current-session.js +164 -0
- zrb/runner/web_controller/static/session/event.js +119 -0
- zrb/runner/web_controller/static/session/past-session.js +144 -0
- zrb/runner/web_util.py +62 -4
- {zrb-1.0.0a18.dist-info → zrb-1.0.0a21.dist-info}/METADATA +9 -52
- {zrb-1.0.0a18.dist-info → zrb-1.0.0a21.dist-info}/RECORD +51 -47
- zrb/runner/web_controller/group_info_ui/controller.py +0 -83
- zrb/runner/web_controller/group_info_ui/partial/group_info.html +0 -2
- zrb/runner/web_controller/group_info_ui/partial/group_li.html +0 -1
- zrb/runner/web_controller/group_info_ui/partial/task_info.html +0 -2
- zrb/runner/web_controller/group_info_ui/partial/task_li.html +0 -1
- zrb/runner/web_controller/group_info_ui/view.html +0 -31
- zrb/runner/web_controller/home_page/partial/group_info.html +0 -2
- zrb/runner/web_controller/home_page/partial/group_li.html +0 -1
- zrb/runner/web_controller/home_page/partial/task_info.html +0 -2
- zrb/runner/web_controller/home_page/partial/task_li.html +0 -1
- zrb/runner/web_controller/task_ui/__init__.py +0 -0
- zrb/runner/web_controller/task_ui/partial/common-util.js +0 -37
- zrb/runner/web_controller/task_ui/partial/main.js +0 -195
- zrb/runner/web_controller/task_ui/partial/show-existing-session.js +0 -97
- zrb/runner/web_controller/task_ui/partial/visualize-history.js +0 -104
- zrb/runner/web_controller/task_ui/view.html +0 -87
- /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/{factory.py → user_repository_factory.py} +0 -0
- /zrb/{builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository → runner/web_controller/group_info_page}/__init__.py +0 -0
- /zrb/runner/web_controller/{group_info_ui → session_page}/__init__.py +0 -0
- {zrb-1.0.0a18.dist-info → zrb-1.0.0a21.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a18.dist-info → zrb-1.0.0a21.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
window.addEventListener("load", async function () {
|
2
|
+
// Get current session
|
3
|
+
if (cfg.SESSION_NAME != "") {
|
4
|
+
CURRENT_SESSION.startPolling();
|
5
|
+
}
|
6
|
+
// set maxStartDate to today
|
7
|
+
const tomorrow = new Date();
|
8
|
+
tomorrow.setDate(tomorrow.getDate() + 1); // Move to the next day
|
9
|
+
tomorrow.setHours(0, 0, 0, 0);
|
10
|
+
const formattedTomorrow = UTIL.toLocalDateInputValue(tomorrow);
|
11
|
+
const maxStartAtInput = document.getElementById("max-start-at-input");
|
12
|
+
maxStartAtInput.value = formattedTomorrow;
|
13
|
+
// set minStartDate to yesterday
|
14
|
+
const today = new Date();
|
15
|
+
today.setHours(0, 0, 0, 0); // Set time to 00:00:00
|
16
|
+
const formattedToday = UTIL.toLocalDateInputValue(today);
|
17
|
+
const minStartAtInput = document.getElementById("min-start-at-input");
|
18
|
+
minStartAtInput.value = formattedToday;
|
19
|
+
});
|
20
|
+
|
21
|
+
|
22
|
+
const submitTaskForm = document.getElementById("submit-task-form");
|
23
|
+
submitTaskForm.addEventListener("input", async function(event) {
|
24
|
+
const currentInput = event.target;
|
25
|
+
const inputs = Array.from(submitTaskForm.querySelectorAll("input[name]"));
|
26
|
+
const inputMap = {};
|
27
|
+
const fixedInputNames = [];
|
28
|
+
for (const input of inputs) {
|
29
|
+
fixedInputNames.push(input.name);
|
30
|
+
if (input === currentInput) {
|
31
|
+
inputMap[input.name] = currentInput.value;
|
32
|
+
break;
|
33
|
+
} else {
|
34
|
+
inputMap[input.name] = input.value;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
const queryString = new URLSearchParams(
|
38
|
+
{query: JSON.stringify(inputMap)}
|
39
|
+
).toString();
|
40
|
+
try {
|
41
|
+
// Send the AJAX request
|
42
|
+
const response = await fetch(`${cfg.INPUT_API_URL}?${queryString}`, {
|
43
|
+
method: "GET",
|
44
|
+
headers: {
|
45
|
+
"Content-Type": "application/json"
|
46
|
+
},
|
47
|
+
});
|
48
|
+
if (response.ok) {
|
49
|
+
const data = await response.json();
|
50
|
+
// Update the values of all subsequent inputs based on the response
|
51
|
+
Object.entries(data).forEach(([key, value]) => {
|
52
|
+
if (fixedInputNames.includes(key)) {
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
const input = submitTaskForm.querySelector(`[name="${key}"]`);
|
56
|
+
input.value = value;
|
57
|
+
});
|
58
|
+
} else {
|
59
|
+
console.error("Failed to fetch updated values:", response.statusText);
|
60
|
+
}
|
61
|
+
} catch (error) {
|
62
|
+
console.error("Error during fetch:", error);
|
63
|
+
}
|
64
|
+
});
|
65
|
+
|
66
|
+
|
67
|
+
function openPastSessionDialog(event) {
|
68
|
+
event.preventDefault();
|
69
|
+
PAST_SESSION.startPolling();
|
70
|
+
const dialog = document.getElementById("past-session-dialog")
|
71
|
+
dialog.showModal();
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
function closePastSessionDialog(event) {
|
76
|
+
event.preventDefault();
|
77
|
+
PAST_SESSION.stopPolling();
|
78
|
+
const dialog = document.getElementById("past-session-dialog")
|
79
|
+
dialog.close();
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
async function submitNewSessionForm(event) {
|
84
|
+
// Prevent the form from submitting the traditional way
|
85
|
+
event.preventDefault();
|
86
|
+
// Select the form
|
87
|
+
const form = document.getElementById("submit-task-form");
|
88
|
+
// Initialize an empty object to hold form data
|
89
|
+
const formData = {};
|
90
|
+
// Iterate through each input in the form
|
91
|
+
Array.from(form.elements).forEach(element => {
|
92
|
+
// Only include inputs with a name attribute and ignore buttons
|
93
|
+
if (element.name && (element.type !== "button" && element.type !== "submit")) {
|
94
|
+
formData[element.name] = element.value;
|
95
|
+
}
|
96
|
+
});
|
97
|
+
// Convert formData to JSON
|
98
|
+
const jsonData = JSON.stringify(formData);
|
99
|
+
try {
|
100
|
+
// Send the AJAX request
|
101
|
+
const response = await fetch(cfg.SESSION_API_URL, {
|
102
|
+
method: "POST",
|
103
|
+
headers: {
|
104
|
+
"Content-Type": "application/json"
|
105
|
+
},
|
106
|
+
body: jsonData
|
107
|
+
});
|
108
|
+
if (response.ok) {
|
109
|
+
const data = await response.json();
|
110
|
+
cfg.SESSION_NAME = data.session_name;
|
111
|
+
history.pushState(null, "", `${cfg.CURRENT_URL}${cfg.SESSION_NAME}`);
|
112
|
+
await CURRENT_SESSION.startPolling();
|
113
|
+
} else {
|
114
|
+
console.error("Error:", response);
|
115
|
+
}
|
116
|
+
} catch (error) {
|
117
|
+
console.error("Error:", error);
|
118
|
+
}
|
119
|
+
}
|
@@ -0,0 +1,144 @@
|
|
1
|
+
const PAST_SESSION = {
|
2
|
+
shouldPoll: true,
|
3
|
+
|
4
|
+
async startPolling() {
|
5
|
+
await this.getAndRenderPastSession(cfg.PAGE);
|
6
|
+
while (this.shouldPoll) {
|
7
|
+
await UTIL.delay(5000);
|
8
|
+
await this.getAndRenderPastSession(cfg.PAGE);
|
9
|
+
}
|
10
|
+
},
|
11
|
+
|
12
|
+
stopPolling() {
|
13
|
+
this.shouldPoll = false;
|
14
|
+
},
|
15
|
+
|
16
|
+
async getAndRenderPastSession(page) {
|
17
|
+
cfg.PAGE=page
|
18
|
+
const minStartAtInput = document.getElementById("min-start-at-input");
|
19
|
+
const minStartAt = UTIL.formatDate(minStartAtInput.value);
|
20
|
+
const maxStartAtInput = document.getElementById("max-start-at-input");
|
21
|
+
const maxStartAt = UTIL.formatDate(maxStartAtInput.value);
|
22
|
+
const queryString = new URLSearchParams({
|
23
|
+
page: page,
|
24
|
+
from: minStartAt,
|
25
|
+
to: maxStartAt,
|
26
|
+
}).toString();
|
27
|
+
try {
|
28
|
+
// Send the AJAX request
|
29
|
+
const response = await fetch(`${cfg.SESSION_API_URL}list?${queryString}`, {
|
30
|
+
method: "GET",
|
31
|
+
headers: {
|
32
|
+
"Content-Type": "application/json"
|
33
|
+
},
|
34
|
+
});
|
35
|
+
if (response.ok) {
|
36
|
+
const {total, data} = await response.json();
|
37
|
+
this.showPastSession(page, total, data);
|
38
|
+
} else {
|
39
|
+
console.error("Error:", response);
|
40
|
+
}
|
41
|
+
} catch (error) {
|
42
|
+
console.error("Error:", error);
|
43
|
+
}
|
44
|
+
},
|
45
|
+
|
46
|
+
showPastSession(page, total, data) {
|
47
|
+
const ul = document.getElementById("past-session-ul");
|
48
|
+
ul.innerHTML = ''; // Clear existing content
|
49
|
+
data.forEach(item => {
|
50
|
+
const taskStatus = item.task_status[item.main_task_name];
|
51
|
+
const finalStatus = UTIL.getFinalTaskStatus(taskStatus);
|
52
|
+
const finalColor = UTIL.getFinalColor(finalStatus);
|
53
|
+
const taskHistories = taskStatus.history;
|
54
|
+
const taskStartTime = taskHistories.length > 0 ? taskHistories[0].time : ""
|
55
|
+
const li = document.createElement('li');
|
56
|
+
const a = document.createElement('a');
|
57
|
+
const dateSpan = document.createElement('span');
|
58
|
+
const statusSpan = document.createElement('span');
|
59
|
+
a.textContent = item.name;
|
60
|
+
a.target = '_blank';
|
61
|
+
a.href = `${cfg.UI_URL}${item.name}`;
|
62
|
+
li.appendChild(a);
|
63
|
+
statusSpan.style.marginLeft = "10px";
|
64
|
+
statusSpan.style.display = 'inline-block';
|
65
|
+
statusSpan.style.width = '15px';
|
66
|
+
statusSpan.style.height = '15px';
|
67
|
+
statusSpan.style.borderRadius = '50%';
|
68
|
+
statusSpan.style.border = '2px solid black';
|
69
|
+
statusSpan.style.backgroundColor = finalColor;
|
70
|
+
li.appendChild(statusSpan);
|
71
|
+
dateSpan.style.marginLeft = "10px";
|
72
|
+
dateSpan.textContent = taskStartTime;
|
73
|
+
li.appendChild(dateSpan);
|
74
|
+
ul.appendChild(li);
|
75
|
+
});
|
76
|
+
const paginationUl = document.getElementById("past-session-pagination-ul");
|
77
|
+
paginationUl.innerHTML = ''; // Clear previous pagination
|
78
|
+
|
79
|
+
const totalPages = Math.ceil(total / 10); // Calculate total pages based on page size
|
80
|
+
const maxPagesToShow = 5; // Number of pages to display around the current page
|
81
|
+
const halfMaxPages = Math.floor(maxPagesToShow / 2);
|
82
|
+
|
83
|
+
// Add first page and previous controls
|
84
|
+
if (page > 0) {
|
85
|
+
paginationUl.appendChild(this.createPageLink("⟪", 0)); // Go to first page
|
86
|
+
paginationUl.appendChild(this.createPageLink("⟨", page - 1)); // Go to previous page
|
87
|
+
}
|
88
|
+
|
89
|
+
let startPage = Math.max(0, page - halfMaxPages);
|
90
|
+
let endPage = Math.min(totalPages - 1, page + halfMaxPages);
|
91
|
+
|
92
|
+
if (page <= halfMaxPages) {
|
93
|
+
endPage = Math.min(totalPages - 1, maxPagesToShow - 1);
|
94
|
+
} else if (page + halfMaxPages >= totalPages) {
|
95
|
+
startPage = Math.max(0, totalPages - maxPagesToShow);
|
96
|
+
}
|
97
|
+
|
98
|
+
if (startPage > 1) {
|
99
|
+
paginationUl.appendChild(this.createEllipsis());
|
100
|
+
}
|
101
|
+
|
102
|
+
// Add page links within the calculated range
|
103
|
+
for (let i = startPage; i <= endPage; i++) {
|
104
|
+
if (i === page) {
|
105
|
+
const pageLi = document.createElement('li');
|
106
|
+
pageLi.textContent = i + 1;
|
107
|
+
paginationUl.append(pageLi)
|
108
|
+
} else {
|
109
|
+
paginationUl.appendChild(this.createPageLink(i + 1, i))
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
// Add ellipsis after the end page if needed
|
114
|
+
if (endPage < totalPages - 2) {
|
115
|
+
paginationUl.appendChild(this.createEllipsis());
|
116
|
+
}
|
117
|
+
|
118
|
+
// Add next and last page controls
|
119
|
+
if (page < totalPages - 1) {
|
120
|
+
paginationUl.appendChild(this.createPageLink("⟩", page + 1)); // Go to next page
|
121
|
+
paginationUl.appendChild(this.createPageLink("⟫", totalPages - 1)); // Go to last page
|
122
|
+
}
|
123
|
+
},
|
124
|
+
|
125
|
+
createPageLink(text, page) {
|
126
|
+
const li = document.createElement('li');
|
127
|
+
const link = document.createElement('a');
|
128
|
+
link.textContent = text;
|
129
|
+
link.href = '#';
|
130
|
+
link.onclick = (e) => {
|
131
|
+
e.preventDefault();
|
132
|
+
this.getAndRenderPastSession(page);
|
133
|
+
};
|
134
|
+
li.appendChild(link);
|
135
|
+
return li;
|
136
|
+
},
|
137
|
+
|
138
|
+
createEllipsis() {
|
139
|
+
const li = document.createElement('li');
|
140
|
+
li.textContent = '...';
|
141
|
+
return li;
|
142
|
+
},
|
143
|
+
|
144
|
+
}
|
zrb/runner/web_util.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
|
1
|
+
import os
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
from zrb.group.any_group import AnyGroup
|
4
|
+
from zrb.runner.web_config import User
|
5
|
+
from zrb.task.any_task import AnyTask
|
6
|
+
from zrb.util.file import read_file
|
7
|
+
from zrb.util.group import get_non_empty_subgroups, get_subtasks
|
6
8
|
|
7
9
|
|
8
10
|
def url_to_args(url: str) -> list[str]:
|
@@ -14,3 +16,59 @@ def node_path_to_url(args: list[str]) -> str:
|
|
14
16
|
pruned_args = [part for part in args if part.strip() != ""]
|
15
17
|
stripped_url = "/".join(pruned_args)
|
16
18
|
return f"/{stripped_url}/"
|
19
|
+
|
20
|
+
|
21
|
+
def get_html_auth_link(user: User) -> str:
|
22
|
+
if user.is_guest and user.is_super_admin:
|
23
|
+
return f"Hi, {user.username}"
|
24
|
+
if user.is_guest:
|
25
|
+
return f'Hi, {user.username} <a href="/login">Login 🔑</a>'
|
26
|
+
return f'Hi, {user.username} <a href="/logout">Logout 🚪</a>'
|
27
|
+
|
28
|
+
|
29
|
+
def get_refresh_token_js(refresh_interval_seconds: int):
|
30
|
+
_DIR = os.path.dirname(__file__)
|
31
|
+
return read_file(
|
32
|
+
os.path.join(_DIR, "refresh-token.template.js"),
|
33
|
+
{"refreshIntervalSeconds": f"{refresh_interval_seconds}"},
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
def get_html_subtask_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
|
38
|
+
subtasks = get_subtasks(parent_group, web_only=True)
|
39
|
+
task_li = "\n".join(
|
40
|
+
[
|
41
|
+
get_html_task_li(parent_url, alias, subtask)
|
42
|
+
for alias, subtask in subtasks.items()
|
43
|
+
if user.can_access_task(subtask)
|
44
|
+
]
|
45
|
+
)
|
46
|
+
if task_li.strip() == "":
|
47
|
+
return ""
|
48
|
+
return f"<h5>Tasks</h5><ul>{task_li}</ul>"
|
49
|
+
|
50
|
+
|
51
|
+
def get_html_task_li(parent_url: str, alias: str, task: AnyTask) -> str:
|
52
|
+
if not parent_url.endswith("/"):
|
53
|
+
parent_url += "/"
|
54
|
+
return f'<li><a href="{parent_url}{alias}">{alias}</a> {task.description}</li>'
|
55
|
+
|
56
|
+
|
57
|
+
def get_html_subgroup_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
|
58
|
+
subgroups = get_non_empty_subgroups(parent_group, web_only=True)
|
59
|
+
group_li = "\n".join(
|
60
|
+
[
|
61
|
+
get_html_group_li(parent_url, alias, subgroup)
|
62
|
+
for alias, subgroup in subgroups.items()
|
63
|
+
if user.can_access_group(subgroup)
|
64
|
+
]
|
65
|
+
)
|
66
|
+
if group_li.strip() == "":
|
67
|
+
return ""
|
68
|
+
return f"<h5>Groups</h5><ul>{group_li}</ul>"
|
69
|
+
|
70
|
+
|
71
|
+
def get_html_group_li(parent_url: str, alias: str, group: AnyGroup) -> str:
|
72
|
+
if not parent_url.endswith("/"):
|
73
|
+
parent_url += "/"
|
74
|
+
return f'<li><a href="{parent_url}{alias}">{alias}</a> {group.description}</li>'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: zrb
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.0a21
|
4
4
|
Summary: Your Automation Powerhouse
|
5
5
|
Home-page: https://github.com/state-alchemists/zrb
|
6
6
|
License: AGPL-3.0-or-later
|
@@ -24,6 +24,7 @@ Requires-Dist: libcst (>=1.5.0,<2.0.0)
|
|
24
24
|
Requires-Dist: litellm (>=1.52.12,<2.0.0)
|
25
25
|
Requires-Dist: pdfplumber (>=0.11.4,<0.12.0) ; extra == "rag"
|
26
26
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
27
|
+
Requires-Dist: python-jose[cryptography] (>=3.3.0,<4.0.0)
|
27
28
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
28
29
|
Project-URL: Documentation, https://github.com/state-alchemists/zrb
|
29
30
|
Project-URL: Repository, https://github.com/state-alchemists/zrb
|
@@ -31,9 +32,11 @@ Description-Content-Type: text/markdown
|
|
31
32
|
|
32
33
|

|
33
34
|
|
35
|
+
[Documentation](https://github.com/state-alchemists/zrb/blob/main/docs/README.md)
|
36
|
+
|
34
37
|
# 🤖 Zrb: Your Automation Powerhouse
|
35
38
|
|
36
|
-
|
39
|
+
Zrb allows you to write your automation tasks in Python and declaratively:
|
37
40
|
|
38
41
|
|
39
42
|
```python
|
@@ -51,59 +54,13 @@ math.add_task(Task(
|
|
51
54
|
))
|
52
55
|
```
|
53
56
|
|
54
|
-
|
55
|
-
|
56
|
-
__Using CLI with arguments__
|
57
|
-
|
58
|
-
```bash
|
59
|
-
zrb math add 4 5
|
60
|
-
```
|
61
|
-
|
62
|
-
Result:
|
63
|
-
|
64
|
-
```
|
65
|
-
9
|
66
|
-
To run again: zrb math add --a=4 --b=5
|
67
|
-
```
|
68
|
-
|
69
|
-
__Using CLI with keyword arguments__
|
70
|
-
|
71
|
-
```bash
|
72
|
-
zrb math add --a 4 --b 5
|
73
|
-
```
|
74
|
-
|
75
|
-
Result:
|
76
|
-
|
77
|
-
```
|
78
|
-
9
|
79
|
-
To run again: zrb math add --a=4 --b=5
|
80
|
-
```
|
81
|
-
|
82
|
-
__Using CLI with incomplete arguments__
|
83
|
-
|
84
|
-
```bash
|
85
|
-
zrb math add 4
|
86
|
-
```
|
87
|
-
|
88
|
-
Result:
|
89
|
-
|
90
|
-
```
|
91
|
-
b [0]: 5
|
92
|
-
9
|
93
|
-
To run again: zrb math add 4
|
94
|
-
```
|
95
|
-
|
96
|
-
__Using Web Interface__
|
97
|
-
|
98
|
-
```bash
|
99
|
-
zrb server start
|
100
|
-
```
|
57
|
+
Once defined, you will be able to access your automation tasks from the CLI, Web Interface, or via HTTP API.
|
101
58
|
|
102
|
-
|
59
|
+
For more complex scenario, you can also defined Task dependencies (upstreams) and retry mechanisms. You can also make a scheduled tasks, just like in Apache Airflow.
|
103
60
|
|
104
|
-
|
61
|
+
Furthermore, Zrb has some builtin tasks to manage monorepo, generate FastAPI application, or play around with LLM.
|
105
62
|
|
106
|
-
|
63
|
+
See the [getting started guide](https://github.com/state-alchemists/zrb/blob/main/docs/recipes/getting-started/README.md) for more information. Or just watch the demo:
|
107
64
|
|
108
65
|
[](https://www.youtube.com/watch?v=W7dgk96l__o)
|
109
66
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
zrb/__init__.py,sha256=
|
1
|
+
zrb/__init__.py,sha256=YY3rfl2gdDLe-t5RMWsvlChSQXv6izw24yv0V1MQ60E,2911
|
2
2
|
zrb/__main__.py,sha256=tCRJm0qtx646ojZP8Rtgu8t_SDdSpply21HbR5poVvk,744
|
3
3
|
zrb/attr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
zrb/attr/type.py,sha256=4TV5gPYMMrKh5V-yB6iRYKCbsXAH_AvGXMsjxKLHcUs,568
|
@@ -64,30 +64,30 @@ zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py,sha256=K
|
|
64
64
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
65
65
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/alembic.ini,sha256=mgQyBAIwdkZZJWLu_FQWPx1FkyaARCNp6-rLqSVvMbA,3723
|
66
66
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py,sha256=jJLY951xnDQoLdRrKQTE0aan73gw2a7Zb_4QCu6qCu4,767
|
67
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py,sha256=
|
68
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py,sha256=
|
67
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py,sha256=qgjykg69zgrVz8V2wN8bBY0ptGwkPp3Ae5G5IZVkhs4,291
|
68
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py,sha256=OIoUcTsYoTFmnzIazSZhQM9-l-7lsG-Fe54rrMpRSp0,222
|
69
69
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py,sha256=3Z-PStpA-7D_LiVO50CRchOY5m77rRhQrWcxq3fBLF4,390
|
70
70
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
|
71
71
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/env.py,sha256=rtUFa4Gaoz3wmq7YfQ-lY8vYA5aWguwe2yvQQ1OLCL8,3343
|
72
72
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/script.py.mako,sha256=U9DYBoBRd_ooogMfRydCUGEjIDZ-aV8OsjBiBrdTvy4,680
|
73
73
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py,sha256=j4tkh9NaTKNMefcy1dUdgRI5CzydUidli7i0Q6Ap-7Q,1021
|
74
74
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py,sha256=ZO-6D7V-KyESQ_e7LjiWRovsSNP5E3KS_oVo77xdFh8,157
|
75
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py,sha256=
|
75
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py,sha256=TdQ38QeVGvqJdLH3Ixdg_R6emcV6pLtX8CFln1lrE5o,1097
|
76
76
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
77
77
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
78
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/factory.py,sha256=-tpEF53042tyorTLvWXpf_ti-w8W8wsvPzOOi_FsqZM,449
|
80
78
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py,sha256=4nz9-PBjm_Jr06nUoHXLj90Ygwm4qgT1Gy5MOMdoRfU,1583
|
81
79
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py,sha256=titxurh5C0sMZ49OTb53EG32QGYzKfZhvHqpyCxlVag,961
|
82
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/
|
80
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py,sha256=-tpEF53042tyorTLvWXpf_ti-w8W8wsvPzOOi_FsqZM,449
|
81
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py,sha256=LxnjFXxpnCKnpv7BqYukdP_W06Ax1NTfGujLAR1RENo,1862
|
82
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py,sha256=R5mK1_XGUnog0AmbNnPiuPfWAWdPanxSeI8v3NJ601E,244
|
83
83
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/alembic.ini,sha256=mgQyBAIwdkZZJWLu_FQWPx1FkyaARCNp6-rLqSVvMbA,3723
|
84
84
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/migration/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
|
85
85
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/migration/env.py,sha256=xQ4UYy6aaHhE0NssPZ6QkeNFlC1KBd07EhDR0NNzj20,3349
|
86
86
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/migration/script.py.mako,sha256=U9DYBoBRd_ooogMfRydCUGEjIDZ-aV8OsjBiBrdTvy4,680
|
87
87
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/migration/versions/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
88
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/migration_metadata.py,sha256=NbIb5ncy6x5RrFD2TZMDwxBK_wDTyJEIvieMRmNpf9M,55
|
89
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py,sha256=
|
90
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py,sha256=
|
89
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py,sha256=O_ZAxrvwQesXRv2Fpy0rEVhWpU5HKoFESlXxrVVCifE,1084
|
90
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py,sha256=VWSyJw-Ou96a5EENn1poa-GlthJZ3Js-Pbn9sY8bndI,1813
|
91
91
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt,sha256=B8CigKAHjauuEyQaKQ-U9g3pAbe70femEScpZgblNbI,90
|
92
92
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
93
93
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py,sha256=vK8Qb5dDd_b5Y9gpehUr5OMSKggp1NlkWSz8ePAa0No,769
|
@@ -120,7 +120,7 @@ zrb/callback/callback.py,sha256=hKefB_Jd1XGjPSLQdMKDsGLHPzEGO2dqrIArLl_EmD0,848
|
|
120
120
|
zrb/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
121
121
|
zrb/cmd/cmd_result.py,sha256=L8bQJzWCpcYexIxHBNsXj2pT3BtLmWex0iJSMkvimOA,597
|
122
122
|
zrb/cmd/cmd_val.py,sha256=hr8Ge0FRe7FZStvkDYnd1MUOOiJW2lDOQqBv338Ymas,963
|
123
|
-
zrb/config.py,sha256=
|
123
|
+
zrb/config.py,sha256=vZHW6ydp-o27FhMkz6aUYwH1UfEPbKacT55hb_GuSMk,3832
|
124
124
|
zrb/content_transformer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
125
125
|
zrb/content_transformer/any_content_transformer.py,sha256=3XHM6ZdsJFXxRD7YlUkv0Gn7-mexsH8c8zdHt3C0x8k,741
|
126
126
|
zrb/content_transformer/content_transformer.py,sha256=vNR8Z_fS7dG2A42O7scDG96JYKBz6IDuFa_B4zMVzZY,2012
|
@@ -140,44 +140,48 @@ zrb/group/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
140
140
|
zrb/group/any_group.py,sha256=1rNcsi5eu_86JAx_6Jy46SK4BTeppcb89MORynJd-4o,1115
|
141
141
|
zrb/group/group.py,sha256=JFmWVEQ9PVy2WCf5pUG74iwL2xcGxXaAjT-NArAeloM,1861
|
142
142
|
zrb/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
143
|
-
zrb/input/any_input.py,sha256=
|
144
|
-
zrb/input/base_input.py,sha256=
|
145
|
-
zrb/input/bool_input.py,sha256=
|
146
|
-
zrb/input/float_input.py,sha256=
|
147
|
-
zrb/input/int_input.py,sha256=
|
148
|
-
zrb/input/option_input.py,sha256=
|
149
|
-
zrb/input/password_input.py,sha256=
|
143
|
+
zrb/input/any_input.py,sha256=0YxEaXvWyG3mWmBgUf3Z0HqtFag-JSoFuBSnfdqvWWI,803
|
144
|
+
zrb/input/base_input.py,sha256=AiSCxxYqJd5rlYsuzO1zqXQQ_ZuJsSONvR7t_m9Kj-I,3161
|
145
|
+
zrb/input/bool_input.py,sha256=zI1fea1k--r57vX61YVRog9sL_O7XX3gS7J3MGE8654,1383
|
146
|
+
zrb/input/float_input.py,sha256=W_FGgnL26l6iaNkWGHDXeu20B9QHAlyHonOVR2evin0,1015
|
147
|
+
zrb/input/int_input.py,sha256=tOgjhR8KYyahcmEto05lLzYtBowBUckwpcX4v-5sJlM,1005
|
148
|
+
zrb/input/option_input.py,sha256=S9IjGNzjPBexMb6BEuyyrPOcb10xjkFwVH02k2v7C2A,1939
|
149
|
+
zrb/input/password_input.py,sha256=C2alr0hgO_YLWf9MDF2H8w0NIIf_DZlDJSdKQwEyM0E,1311
|
150
150
|
zrb/input/str_input.py,sha256=NevZHX9rf1g8eMatPyy-kUX3DglrVAQpzvVpKAzf7bA,81
|
151
|
-
zrb/input/text_input.py,sha256=
|
151
|
+
zrb/input/text_input.py,sha256=7i0lvWYw79ILp0NEOBn-Twwnv7sBEgxJsqVaai6LzAA,3033
|
152
152
|
zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
153
|
-
zrb/runner/cli.py,sha256
|
154
|
-
zrb/runner/
|
153
|
+
zrb/runner/cli.py,sha256=ycus4N2T4sTdvLSxocyqjK3Atacm2vGRwpZuPhk9dDA,6573
|
154
|
+
zrb/runner/common_util.py,sha256=JYBgNPSGyJHZo0X-Qp9sDi4B14NdcTi20n1fJP4SW3M,1298
|
155
|
+
zrb/runner/refresh-token.template.js,sha256=v_nF7nU1AXp-KtsHNNzamhciEi7NCSTPEDT5hCxn29g,735
|
156
|
+
zrb/runner/web_app.py,sha256=OjLYX3tRw1PiLkQdrmZkZ_cykknw4W9L8NFODL3tUGA,12866
|
157
|
+
zrb/runner/web_config.py,sha256=pF6PE92fSAwsG1IobFbW4TGJY3Z4TUnlRzX1qxLFyqY,9428
|
155
158
|
zrb/runner/web_controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
156
|
-
zrb/runner/web_controller/
|
157
|
-
zrb/runner/web_controller/
|
158
|
-
zrb/runner/web_controller/
|
159
|
-
zrb/runner/web_controller/
|
160
|
-
zrb/runner/web_controller/
|
161
|
-
zrb/runner/web_controller/group_info_ui/partial/task_li.html,sha256=x5Pqa_iN0IyUvzojseGUrHm2Y-xUeO8OFb7Zagui2g0,62
|
162
|
-
zrb/runner/web_controller/group_info_ui/view.html,sha256=7yIMx0yxSsmdmwPvXkm8tLgbmw7iqW068xzfFROmh9Y,836
|
159
|
+
zrb/runner/web_controller/error_page/controller.py,sha256=Dh2vanfPMvc5aAW0rLYOd2WwUrcO1fGdNVk80-8Qzzs,857
|
160
|
+
zrb/runner/web_controller/error_page/view.html,sha256=VI-q18Rffyn3T_EQptvn7tZ4qIYLVxj82YbazbXnYfY,1156
|
161
|
+
zrb/runner/web_controller/group_info_page/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
162
|
+
zrb/runner/web_controller/group_info_page/controller.py,sha256=PBPCyVXILa7gCIC8d-0Exip7EAnTm3ch5GWe1Fs3WxI,1311
|
163
|
+
zrb/runner/web_controller/group_info_page/view.html,sha256=wISun627ciFZcvGpxANG0pr1zgUtSd1m1rNhCAYjRQw,1280
|
163
164
|
zrb/runner/web_controller/home_page/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
164
|
-
zrb/runner/web_controller/home_page/controller.py,sha256=
|
165
|
-
zrb/runner/web_controller/home_page/
|
166
|
-
zrb/runner/web_controller/
|
167
|
-
zrb/runner/web_controller/
|
168
|
-
zrb/runner/web_controller/
|
169
|
-
zrb/runner/web_controller/
|
165
|
+
zrb/runner/web_controller/home_page/controller.py,sha256=2e_Oarts9nnau7ZSdBDiqqvsw7qd7jsIB14BXAsu4FI,1008
|
166
|
+
zrb/runner/web_controller/home_page/view.html,sha256=ee0O1bgoZO0qYVqaa67ad7wX_Zawqsy6F-ioxbjEQGk,1070
|
167
|
+
zrb/runner/web_controller/login_page/controller.py,sha256=vCRGgp8mW5JnYt-sPzWdJLLqlaARQO2zTOHAcPzkqrw,733
|
168
|
+
zrb/runner/web_controller/login_page/view.html,sha256=-MeHcSb3r0ouUhs-4aFgrlPjV_V7iz2a6PkobVpk77c,1761
|
169
|
+
zrb/runner/web_controller/logout_page/controller.py,sha256=0mX3wyY5jNtI1Jnxfl_7N8fHtLfBwPE81x9yh2zO_u4,764
|
170
|
+
zrb/runner/web_controller/logout_page/view.html,sha256=O17ow4-KMbxTkwaQgR880Rlt1B9pnHrRTlgu5nsM4LA,1324
|
171
|
+
zrb/runner/web_controller/session_page/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
172
|
+
zrb/runner/web_controller/session_page/controller.py,sha256=q7O8BeytX9kWyU24CMPXVW2cjkN5BQG5tAkr_kuUOXY,2632
|
173
|
+
zrb/runner/web_controller/session_page/partial/input.html,sha256=X2jy0q7TLQGP853exZMed0lqPezL3gzn6mnhB5QKfkc,178
|
174
|
+
zrb/runner/web_controller/session_page/view.html,sha256=CwrIiPJAwHEEIVNp_wkTzW7kQJjTh41FSDamCswI3S8,3593
|
175
|
+
zrb/runner/web_controller/static/common.css,sha256=u5rGLsPx2943z324iQ2X81krM3z-kc-8e1SkBdYAvKU,157
|
170
176
|
zrb/runner/web_controller/static/favicon-32x32.png,sha256=yu9AIU4k_qD4YHpul6XwJgOxIbmu0thv9ymm2QOsrAk,1456
|
171
|
-
zrb/runner/web_controller/static/
|
172
|
-
zrb/runner/web_controller/
|
173
|
-
zrb/runner/web_controller/
|
174
|
-
zrb/runner/web_controller/
|
175
|
-
zrb/runner/web_controller/
|
176
|
-
zrb/runner/web_controller/
|
177
|
-
zrb/runner/web_controller/
|
178
|
-
zrb/runner/
|
179
|
-
zrb/runner/web_controller/task_ui/view.html,sha256=SARL-Dt03ar8IT9RJt7ULJLsjRm5u8K_F4VFwQwhxAs,2668
|
180
|
-
zrb/runner/web_util.py,sha256=FBMnS7qMp31ogm0pCZBObNjrlopIwzYM7UuZjCX1n8Q,428
|
177
|
+
zrb/runner/web_controller/static/login/event.js,sha256=1-NxaUwU-X7Tu2RAwVkzU7gngS0OdooH7Ple4_KDrh4,1135
|
178
|
+
zrb/runner/web_controller/static/logout/event.js,sha256=MfZxrTa2yL49Lbh7cCZDdqsIcf9e1q3W8-WjmZXV5pA,692
|
179
|
+
zrb/runner/web_controller/static/pico.min.css,sha256=_Esfkjs_U_igYn-tXBUaK3AEKb7d4l9DlmaOiw9bXfI,82214
|
180
|
+
zrb/runner/web_controller/static/session/common-util.js,sha256=t7_s5DXgMyZlT8L8LYZTkzOT6vWVeZvmCKjt-bflQY0,2117
|
181
|
+
zrb/runner/web_controller/static/session/current-session.js,sha256=JV0VRFeizFigPqQiXIeW3By36FDDZhkRM_a8UI4mh-E,6509
|
182
|
+
zrb/runner/web_controller/static/session/event.js,sha256=Bd3iW_XqWDlD6gJtSvFju-eT8vQzpkLHOcQU85quCWk,4154
|
183
|
+
zrb/runner/web_controller/static/session/past-session.js,sha256=RwGJYKSp75K8NZ-iZP58XppWgdzkiKFaiC5wgcMLxDo,5470
|
184
|
+
zrb/runner/web_util.py,sha256=9zAH9FkPM7anVNjRcwTjHyfFocfwpksaWQVYth_nuBc,2464
|
181
185
|
zrb/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
182
186
|
zrb/session/any_session.py,sha256=x57mS15E-AfUjdVxwOWEzCBjW32zjer7WoeBw0guoDc,5266
|
183
187
|
zrb/session/session.py,sha256=b89UdwPs0U9XXmTHNhCXFmcYXxuRVhNr94Dp_bVO3n4,9827
|
@@ -234,7 +238,7 @@ zrb/util/string/name.py,sha256=8picJfUBXNpdh64GNaHv3om23QHhUZux7DguFLrXHp8,1163
|
|
234
238
|
zrb/util/todo.py,sha256=1nDdwPc22oFoK_1ZTXyf3638Bg6sqE2yp_U4_-frHoc,16015
|
235
239
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
236
240
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
237
|
-
zrb-1.0.
|
238
|
-
zrb-1.0.
|
239
|
-
zrb-1.0.
|
240
|
-
zrb-1.0.
|
241
|
+
zrb-1.0.0a21.dist-info/METADATA,sha256=GzXMD38Yc32hIwuW55Pe1tMFB3_2j56o8Iz11qJtQOo,4185
|
242
|
+
zrb-1.0.0a21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
243
|
+
zrb-1.0.0a21.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
244
|
+
zrb-1.0.0a21.dist-info/RECORD,,
|