backlogops-gui 0.1__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.
@@ -0,0 +1,165 @@
1
+ #! /usr/local/bin/python3
2
+ """Build tables of a backlog and its releases with cell formatting.
3
+
4
+ A backlog and its releases are shown as two tables. The table data and the
5
+ cell formatting are derived from the same formatting the file writer uses,
6
+ so the on-screen colors match a written spreadsheet: the status cell and the
7
+ estimated-ready-date cell are highlighted by the format rules, and the other
8
+ cells are left plain. The columns are the union of the field names met in the
9
+ rows, kept in first-seen order, and every cell is rendered as text so the
10
+ table can show any value type.
11
+ """
12
+
13
+ # Copyright (c) 2026, Tom Björkholm
14
+ # MIT License
15
+
16
+ import tkinter as tk
17
+ from tkinter import font as tkfont
18
+ from tkinter import ttk
19
+ from typing import Sequence
20
+ from tableio import Color, Fmt, Value, ValueFmt
21
+ from backlogops import (
22
+ BacklogReleases, FormatRules, format_backlog, format_releases)
23
+
24
+ COLUMN_WIDTH = 120
25
+ BLANK_CELL = ValueFmt(value=None, fmt=Fmt())
26
+ HIGHLIGHT_FILL = {Color.RED: '#ffd6d6', Color.GREEN: '#d6f5d6',
27
+ Color.YELLOW: '#fff3bf'}
28
+
29
+
30
+ def _columns(rows: Sequence[dict[str, ValueFmt]]) -> list[str]:
31
+ """Return the column names met in the rows, in first-seen order."""
32
+ columns: list[str] = []
33
+ for row in rows:
34
+ for name in row:
35
+ if name not in columns:
36
+ columns.append(name)
37
+ return columns
38
+
39
+
40
+ def _cell_text(value: Value) -> str:
41
+ """Return one cell value rendered as display text."""
42
+ return '' if value is None else str(value)
43
+
44
+
45
+ def _table(rows: Sequence[dict[str, ValueFmt]]
46
+ ) -> tuple[list[str], list[list[ValueFmt]]]:
47
+ """Return the columns and column-aligned formatted rows.
48
+
49
+ Each row becomes one cell per column, in column order, so a cell that a
50
+ row does not have becomes a blank, unformatted cell.
51
+ """
52
+ columns = _columns(rows)
53
+ cells = [[row.get(name, BLANK_CELL) for name in columns] for row in rows]
54
+ return columns, cells
55
+
56
+
57
+ def backlog_table(data: BacklogReleases
58
+ ) -> tuple[list[str], list[list[ValueFmt]]]:
59
+ """Return the columns and formatted rows for the backlog table."""
60
+ return _table(format_backlog(data.backlog, FormatRules()))
61
+
62
+
63
+ def release_table(data: BacklogReleases
64
+ ) -> tuple[list[str], list[list[ValueFmt]]]:
65
+ """Return the columns and formatted rows for the releases table."""
66
+ return _table(format_releases(data.releases, FormatRules()))
67
+
68
+
69
+ def _tag_name(fmt: Fmt) -> str:
70
+ """Return a stable tag name identifying one cell format."""
71
+ return f'fmt-{int(fmt.bold)}{int(fmt.italic)}-{fmt.highlight.value}'
72
+
73
+
74
+ def _tag_font(tree: ttk.Treeview, fmt: Fmt) -> tuple[str, int, str]:
75
+ """Return a font descriptor for the bold and italic of a format."""
76
+ base = tkfont.nametofont('TkDefaultFont', root=tree)
77
+ styles = ' '.join(name for name, on in
78
+ (('bold', fmt.bold), ('italic', fmt.italic)) if on)
79
+ return (base.actual('family'), base.actual('size'), styles)
80
+
81
+
82
+ def _ensure_tag(tree: ttk.Treeview, fmt: Fmt) -> str:
83
+ """Configure and return the tag for one non-plain cell format."""
84
+ name = _tag_name(fmt)
85
+ tree.tag_configure(name, background=HIGHLIGHT_FILL.get(fmt.highlight, ''),
86
+ font=_tag_font(tree, fmt))
87
+ return name
88
+
89
+
90
+ def _format_cell(tree: ttk.Treeview, item: str, column: str, fmt: Fmt) -> None:
91
+ """Color one table cell, leaving plain cells untouched."""
92
+ if fmt == Fmt():
93
+ return
94
+ tag = _ensure_tag(tree, fmt)
95
+ tree.tk.call(str(tree), 'tag', 'cell', 'add', tag, (item, column))
96
+
97
+
98
+ def supports_cell_tags(tree: ttk.Treeview) -> bool:
99
+ """Return whether this Tk build supports per-cell Treeview tags.
100
+
101
+ Per-cell tags are a Tk 8.7+ feature. On an older Tk the ``tag cell``
102
+ subcommand does not exist, so the probe raises and coloring falls back
103
+ to whole-row tags, which Tk has supported for far longer.
104
+ """
105
+ try:
106
+ tree.tk.call(str(tree), 'tag', 'cell', 'has', 'fmt-probe')
107
+ except tk.TclError:
108
+ return False
109
+ return True
110
+
111
+
112
+ def _row_format(row: Sequence[ValueFmt]) -> Fmt:
113
+ """Return the first non-plain cell format in a row, else plain."""
114
+ for cell in row:
115
+ if cell.fmt != Fmt():
116
+ return cell.fmt
117
+ return Fmt()
118
+
119
+
120
+ def _color_cells(tree: ttk.Treeview, item: str, columns: Sequence[str],
121
+ row: Sequence[ValueFmt]) -> None:
122
+ """Color each formatted cell of an inserted row separately."""
123
+ for column, cell in zip(columns, row):
124
+ _format_cell(tree, item, column, cell.fmt)
125
+
126
+
127
+ def _insert_row(tree: ttk.Treeview, columns: Sequence[str],
128
+ row: Sequence[ValueFmt], cell_tags: bool) -> None:
129
+ """Insert one row as text and color it per cell or per row.
130
+
131
+ With per-cell tags every formatted cell keeps its own color. Without
132
+ them the whole row takes the format of its first formatted cell, so an
133
+ older Tk still highlights the row instead of failing to build the table.
134
+ """
135
+ values = [_cell_text(cell.value) for cell in row]
136
+ if cell_tags:
137
+ item = tree.insert('', 'end', values=values)
138
+ _color_cells(tree, item, columns, row)
139
+ return
140
+ fmt = _row_format(row)
141
+ tags = () if fmt == Fmt() else (_ensure_tag(tree, fmt),)
142
+ tree.insert('', 'end', values=values, tags=tags)
143
+
144
+
145
+ def make_table(parent: tk.Misc, columns: Sequence[str],
146
+ rows: Sequence[Sequence[ValueFmt]], width: int = COLUMN_WIDTH,
147
+ stretch: bool = True) -> ttk.Treeview:
148
+ """Create a read-only Treeview showing the given columns and rows.
149
+
150
+ Each cell is colored by the format rules, so a late estimate or a done
151
+ or rejected status appears with the same highlight and font as in a
152
+ written spreadsheet. On a Tk too old for per-cell tags the whole row is
153
+ colored instead, so the table still builds and shows the highlight. When
154
+ ``stretch`` is True the columns share the table width; when False each
155
+ column keeps ``width`` pixels, so a table with few columns stays narrow
156
+ instead of spreading across the whole width.
157
+ """
158
+ tree = ttk.Treeview(parent, columns=list(columns), show='headings')
159
+ cell_tags = supports_cell_tags(tree)
160
+ for name in columns:
161
+ tree.heading(name, text=name)
162
+ tree.column(name, width=width, stretch=stretch)
163
+ for row in rows:
164
+ _insert_row(tree, columns, row, cell_tags)
165
+ return tree
@@ -0,0 +1,63 @@
1
+ #! /usr/local/bin/python3
2
+ """Tcl/Tk version checks for the backlog operations GUI."""
3
+
4
+ # Copyright (c) 2026, Tom Björkholm
5
+ # MIT License
6
+
7
+ import tkinter as tk
8
+ from typing import Optional
9
+
10
+
11
+ MIN_TCLTK_VERSION = (9, 0, 2)
12
+ MIN_TCLTK_VERSION_TEXT = '9.0.2'
13
+
14
+
15
+ def _parse_tcltk_version(version_text: str) -> Optional[tuple[int, int, int]]:
16
+ """Return a comparable Tcl/Tk version tuple, or None if malformed."""
17
+ parts = version_text.split('.')
18
+ if len(parts) != 3:
19
+ return None
20
+ version_parts: list[int] = []
21
+ for part in parts:
22
+ if not part.isdecimal():
23
+ return None
24
+ version_parts.append(int(part))
25
+ return (version_parts[0], version_parts[1], version_parts[2])
26
+
27
+
28
+ def _old_version_warning(version_text: str) -> str:
29
+ """Return the warning text for an older Tcl/Tk version."""
30
+ return (
31
+ 'This application was developed for Tcl/Tk version '
32
+ f'{MIN_TCLTK_VERSION_TEXT} or newer, but you are running version '
33
+ f'{version_text}. This may affect the functionality.'
34
+ )
35
+
36
+
37
+ def _bad_version_warning(version_text: str) -> str:
38
+ """Return the warning text for malformed or unreadable version data."""
39
+ return (
40
+ 'This application was developed for Tcl/Tk version '
41
+ f'{MIN_TCLTK_VERSION_TEXT} or newer, but the running Tcl/Tk version '
42
+ f'value {version_text!r} is malformed or cannot be read. '
43
+ 'This may affect the functionality.'
44
+ )
45
+
46
+
47
+ def warning_for_version(version_text: str) -> Optional[str]:
48
+ """Return a warning for unsupported Tcl/Tk versions, if needed."""
49
+ version_tuple = _parse_tcltk_version(version_text)
50
+ if version_tuple is None:
51
+ return _bad_version_warning(version_text)
52
+ if version_tuple < MIN_TCLTK_VERSION:
53
+ return _old_version_warning(version_text)
54
+ return None
55
+
56
+
57
+ def check_tcltk_version(root: tk.Tk) -> Optional[str]:
58
+ """Return a warning if the running Tcl/Tk version may be unsuitable."""
59
+ try:
60
+ version_value = root.tk.call('info', 'patchlevel')
61
+ except (RuntimeError, tk.TclError) as error:
62
+ return _bad_version_warning(str(error))
63
+ return warning_for_version(str(version_value))
@@ -0,0 +1,259 @@
1
+ Metadata-Version: 2.4
2
+ Name: backlogops-gui
3
+ Version: 0.1
4
+ Summary: Graphical user interface for backlog operations.
5
+ Author: Tom Björkholm
6
+ Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://bitbucket.org/tom-bjorkholm/backlog-ops
9
+ Project-URL: Source code, https://bitbucket.org/tom-bjorkholm/backlog-ops
10
+ Project-URL: Documentation, https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/
11
+ Keywords: backlog,release planning,agile,scrum,scheduling,roadmap,project management,product owner,product management
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Development Status :: 3 - Alpha
18
+ Classifier: Intended Audience :: End Users/Desktop
19
+ Classifier: Intended Audience :: Information Technology
20
+ Classifier: Topic :: Office/Business :: Scheduling
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.txt
24
+ Requires-Dist: backlogops>=0.1
25
+ Requires-Dist: argcomplete>=3.6.3
26
+ Dynamic: author
27
+ Dynamic: license-file
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+
31
+ # backlogops-gui
32
+
33
+ There are 3 related packages for backlog operations:
34
+
35
+ - backlogops: a collection of library functions to manipulate backlogs
36
+
37
+ - backlogops-cli: command line interface to use the functions in the library.
38
+ This is just a thin wrapper around the library functions. It serves a dual
39
+ purpose as both an example of how to use the library and as a tool for the
40
+ user to use the library.
41
+
42
+ - backlogops-gui: graphical user interface to use the functions in the library.
43
+ It is based on TkInter. The ambition is to keep it as a thin wrapper around
44
+ the library.
45
+
46
+ ## Available functionality
47
+
48
+ The following functionality is available in all 3 packages:
49
+
50
+ - Reading backlog and releases from file types that TableIO supports reading
51
+ from (Currently CSV, Excel, and ODS).
52
+
53
+ - Writing backlog and releases to file types that TableIO supports writing to
54
+ (Currently CSV, Excel, ODS and 9 other file formats).
55
+
56
+ - File format is detected from the file extension, but may be overridden.
57
+
58
+ - Adjust release content to fit the planned release dates.
59
+
60
+ - Create a demonstration backlog and releases (for exploring the features).
61
+
62
+ - Estimate ready date for the backlog items based on available teams, team
63
+ velocity, vacation dates, periods with half time work, etc.
64
+
65
+ - Extract backlog keys at given backlog item levels.
66
+
67
+ - Reorder the backlog so that the dependencies are satisfied.
68
+
69
+ - Reorder the backlog so that items identified by keys in a list come first. If
70
+ the key is at a higher level it will bring all items it is a parent of in
71
+ front of it (recursively).
72
+
73
+ - Set planned release dates from the estimated release dates.
74
+
75
+ - Calculate the release dates from the backlog items estimated ready dates, with
76
+ a configurable buffer time.
77
+
78
+ - Validate the backlog and releases for consistency.
79
+
80
+ - A wizard to create an available teams configuration.
81
+
82
+ ## The operating model
83
+
84
+ The operating model that most of the functionality is designed for is that the
85
+ teams work off a single backlog in the order of the backlog. The backlog items
86
+ are ordered by priority and dependencies to allow the teams to work in the
87
+ backlog order. Each backlog item and each release may have a planned ready date,
88
+ that records what has been communicated to the customer. Each backlog item and
89
+ each release may have an estimated ready date, that is calculated from the
90
+ current backlog state, the team velocity, and what we know about the
91
+ availability of the team members.
92
+
93
+ ## The backlog item fields
94
+
95
+ Each backlog item has the following fields that are used by the algorithms in
96
+ the library:
97
+
98
+ - key: The key of the backlog item. Required. Must be unique. Must not be empty,
99
+ must not contain whitespace and must not contain any of the characters , . ; :
100
+ ( ) \[ \] \{ \}.
101
+
102
+ - level: The level of the backlog item. Required. Must be an integer.
103
+
104
+ - title: The title of the backlog item. Required.
105
+
106
+ - story_points: The story points of the backlog item. Required.
107
+
108
+ - status: The status of the backlog item. Required.
109
+
110
+ - parent_key: The key of the parent backlog item. Optional. Must exist as a key
111
+ in the backlog. Parent keys are used to build the hierarchy of the backlog.
112
+ The parent key must be at a higher level than the current item. Parent keys
113
+ introduce implicit dependencies between items: the current item cannot start
114
+ before the parent item starts, and the parent item cannot finish before all
115
+ its children have finished.
116
+
117
+ - release: The release of the backlog item. Optional. Follows the same character
118
+ rules as the key. Must not be empty string.
119
+
120
+ - team: The team responsible for the backlog item. Optional. Must not be empty
121
+ string. Must be a valid team name. If None the item can be done by any team.
122
+ If not None. the item can only be done by the specified team.
123
+
124
+ - depends_on_f2s: The list of keys of the backlog items that must have been
125
+ finished before the current item can start. May be empty.
126
+
127
+ - depends_on_f2f: The list of keys of the backlog items that must have been
128
+ finished before the current item can finish. May be empty.
129
+
130
+ - depends_on_s2s: The list of keys of the backlog items that must have been
131
+ started before the current item can start. May be empty.
132
+
133
+ - planned_ready_date: The planned ready date of the backlog item. The date that
134
+ is communicated to the customer. Optional.
135
+
136
+ - estimated_ready_date: The estimated ready date of the backlog item. Optional.
137
+
138
+ Additionally each backlog item can have any number of other fields.
139
+
140
+ ## Installing backlogops-gui
141
+
142
+ ### On macOS and Linux
143
+
144
+ To install backlogops-gui on macOS and Linux, run the following command:
145
+
146
+ ````sh
147
+ pip3 install --upgrade backlogops-gui
148
+ ````
149
+
150
+ ### On Microsoft Windows
151
+
152
+ To install backlogops-gui on Microsoft Windows, run the following command:
153
+
154
+ ````sh
155
+ pip install --upgrade backlogops-gui
156
+ ````
157
+
158
+ ## API documentation
159
+
160
+ For more detailed code documentation, see the API documentation:
161
+
162
+ - [Library public API](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_api.md)
163
+
164
+ - [Library protected API](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_protected_api.md)
165
+
166
+ - [Library public CLI](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_cli.md)
167
+
168
+ - [Library protected CLI](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_protected_cli.md)
169
+
170
+ - [Library public GUI](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_gui.md)
171
+
172
+ - [Library protected GUI](https://bitbucket.org/tom-bjorkholm/backlog-ops/src/master/doc/backlogops_protected_gui.md)
173
+
174
+ ## Graphical user interface for backlog manipulation
175
+
176
+ Most of the functionality in the backlogops backlog operations library
177
+ is made available for GUI users in this GUI application.
178
+
179
+ ### Tkinter
180
+
181
+ The Graphical user interface is based on
182
+ [Tkinter](https://docs.python.org/3/library/tkinter.html). Tkinter
183
+ is based on [Tcl/Tk](https://en.wikipedia.org/wiki/Tk_(software)).
184
+
185
+ For full functionality you need Tk version 9.0.2 or newer.
186
+
187
+ ## First startup
188
+
189
+ Start the application on Linux or mac with command
190
+ ````sh
191
+ python3 -m backlogops_gui
192
+ python3 -m backlogops_gui -c config_file.cfg
193
+ ````
194
+ or on Microsoft Windows with command
195
+ ````sh
196
+ python -m backlogops_gui
197
+ python -m backlogops_gui -c config_file.cfg
198
+ ````
199
+
200
+ At first startup you do not have any configuration file yet,
201
+ so when you start the application it will start the configuration
202
+ wizard.
203
+
204
+ ## Main window
205
+
206
+ The main window has some informative text, but the functionality
207
+ is in the menus.
208
+
209
+ - File
210
+
211
+ - Read backlog...: Read in a file with a backlog and list of releases.
212
+ A new backlog window will be opened with the read in backlog.
213
+
214
+ - New demo backlog: Create a demo backlog with some backlog items and
215
+ releases. A new backlog window will be opened with the demo backlog.
216
+
217
+ - Configuration
218
+
219
+ - Run teams wizard...: this lets you configure the teams that work on
220
+ the backlog and also other aspects like the dates the company is
221
+ closed for vacation, and preset configuration for the inputs or
222
+ outputs you want to use.
223
+
224
+ - Write configuration...: This lets you write the configuration you
225
+ have in application to a file.
226
+
227
+ ## Backlog window
228
+
229
+ The backlog window shows 2 read-only tables: one with the backlog and
230
+ one with the list of releases. You will want to use the menus.
231
+
232
+ - Backlog
233
+
234
+ - Order by keys...
235
+
236
+ - Order by dependencies...
237
+
238
+ - Estimate ready date...
239
+
240
+ - Set planned date from estimated
241
+
242
+ - Adjust release content
243
+
244
+ - Adjust planned release dates...
245
+
246
+ - Extract keys...
247
+
248
+ - Save to file...
249
+
250
+ - Close
251
+
252
+ ## Test summary
253
+
254
+ - Test result: 1066 passed in 16s
255
+ - No flake8 warnings.
256
+ - No mypy errors found.
257
+ - No python layout warnings.
258
+ - Built version(s): 0.1
259
+ - Build and test using Python 3.14.6
@@ -0,0 +1,17 @@
1
+ backlogops_gui/__init__.py,sha256=bG-OmvN7VdaaAC9O0Ru0vaoURmCtWMejK_oVzj7D6BE,146
2
+ backlogops_gui/__main__.py,sha256=znA2bdCvVMLKbvr-EllzmOV5Ywcmg6Ioi7B1Ak_o6Ck,231
3
+ backlogops_gui/application.py,sha256=xHz37G5_jFFGWODFj4LxvbIcZvKuN-QuYaJQqQJiu2s,13042
4
+ backlogops_gui/backlog_io.py,sha256=Bya7ft-ThT61Ormn2C0xcl2C5U7Twi-eu56PnTjHgH8,2867
5
+ backlogops_gui/backlog_window.py,sha256=6YYJClBIYlcVOAGWCwbLs0yrCXZ5gowfz7vE14dxypw,19162
6
+ backlogops_gui/gui_wizard.py,sha256=iAsBdEy7hUhPAHTpbRWOyjQvZpPV08SF0p9jTMmhBgU,9778
7
+ backlogops_gui/io_dialogs.py,sha256=s4x4mpY8QbKaulCXnnAUoD1HDFsK61sMRKjSuqVcyXk,18818
8
+ backlogops_gui/log_buffer.py,sha256=_CHs_XhJoUksNrBCcxCBj4NYtyW0Hfur1n4nT5yrcWo,1711
9
+ backlogops_gui/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ backlogops_gui/table_view.py,sha256=0bwfMr0SRbtDmLU3RSrCfSmuGDvL-FIDm-MysMWbrrQ,6391
11
+ backlogops_gui/tcltk_version.py,sha256=ZsjFXryqMDz7-fFGbxqfJ4BJnTIFQd3M6FA2qrnuK3Y,2168
12
+ backlogops_gui-0.1.dist-info/licenses/LICENSE.txt,sha256=YbzYf1byKHV7rKnb_zN_ouS8n9ttzGcYHpfTdTf-dPk,1072
13
+ backlogops_gui-0.1.dist-info/METADATA,sha256=F2v1SAii71nXc-0NXoTSlxXohvfK0ojqyV4BOX2DAJE,9039
14
+ backlogops_gui-0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
15
+ backlogops_gui-0.1.dist-info/entry_points.txt,sha256=2SeV_ecu1v2m3EC9ZfuMCJLAg2BmVzLc2yVT-838DI4,63
16
+ backlogops_gui-0.1.dist-info/top_level.txt,sha256=j-uzwBPQNrA5rcDs3OR7O91XSKFg-2Sr25UT5RUM03M,15
17
+ backlogops_gui-0.1.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
+ [gui_scripts]
2
+ backlogops-gui = backlogops_gui.application:main
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tom Björkholm
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.
22
+
@@ -0,0 +1 @@
1
+ backlogops_gui