lanscape 2.2.1a1__py3-none-any.whl → 2.3.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.
@@ -98,6 +98,10 @@ class Device(BaseModel):
98
98
  if self.alive:
99
99
  self.hostname = self._get_hostname()
100
100
  self._get_mac_addresses()
101
+ if not self.manufacturer:
102
+ self.manufacturer = self._get_manufacturer(
103
+ self.get_mac()
104
+ )
101
105
 
102
106
  # Fallback for pydantic v1: use dict() and enrich output
103
107
  if not _PYD_V2:
@@ -138,18 +142,29 @@ class Device(BaseModel):
138
142
  @timeout_enforcer(enforcer_timeout, False)
139
143
  def do_test():
140
144
  for attempt in range(port_config.retries + 1):
141
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
142
- sock.settimeout(port_config.timeout)
145
+ sock = None
143
146
  try:
147
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
148
+ sock.settimeout(port_config.timeout)
144
149
  result = sock.connect_ex((self.ip, port))
145
150
  if result == 0:
146
151
  if port not in self.ports:
147
152
  self.ports.append(port)
148
153
  return True
154
+ except OSError as e:
155
+ # Handle socket creation failures (e.g., "Too many open files")
156
+ # Log and continue to retry if attempts remain
157
+ log = logging.getLogger('Device.test_port')
158
+ log.debug(f"OSError on {self.ip}:{port} attempt {attempt + 1}: {e}")
149
159
  except Exception:
150
160
  pass # Connection failed, try again if retries remain
151
161
  finally:
152
- sock.close()
162
+ # Always close socket if it was created
163
+ if sock is not None:
164
+ try:
165
+ sock.close()
166
+ except Exception:
167
+ pass # Ignore errors during cleanup
153
168
 
154
169
  # Wait before retry (except on last attempt)
155
170
  if attempt < port_config.retries:
@@ -154,7 +154,9 @@ def get_port_probes(port: int, strategy: ServiceScanStrategy):
154
154
 
155
155
  def scan_service(ip: str, port: int, cfg: ServiceScanConfig) -> str:
156
156
  """
157
- Synchronous function that attempts to identify the service running on a given port.
157
+ Synchronous function that attempts to identify the service
158
+ running on a given port.
159
+ TODO: This is AI slop and needs to be reworked properly.
158
160
  """
159
161
 
160
162
  async def _async_scan_service(
@@ -183,5 +185,38 @@ def scan_service(ip: str, port: int, cfg: ServiceScanConfig) -> str:
183
185
  log.debug(traceback.format_exc())
184
186
  return "Unknown"
185
187
 
186
- # Use asyncio.run to execute the asynchronous logic synchronously
187
- return asyncio.run(_async_scan_service(ip, port, cfg=cfg))
188
+ # Create and properly manage event loop to avoid file descriptor leaks
189
+ # Using new_event_loop + explicit close is safer in threaded environments
190
+ # than asyncio.run() which can leave resources open under heavy load
191
+ loop = None
192
+ try:
193
+ try:
194
+ # Try to get existing loop first (if running in async context)
195
+ loop = asyncio.get_running_loop()
196
+ # If we're already in an async context, just await directly
197
+ return asyncio.run_coroutine_threadsafe(
198
+ _async_scan_service(ip, port, cfg=cfg), loop
199
+ ).result(timeout=cfg.timeout + 5)
200
+ except RuntimeError:
201
+ # No running loop, create a new one
202
+ loop = asyncio.new_event_loop()
203
+ asyncio.set_event_loop(loop)
204
+ try:
205
+ return loop.run_until_complete(_async_scan_service(ip, port, cfg=cfg))
206
+ finally:
207
+ # Clean up the loop properly
208
+ try:
209
+ # Cancel all remaining tasks
210
+ pending = asyncio.all_tasks(loop)
211
+ for task in pending:
212
+ task.cancel()
213
+ # Run loop once more to process cancellations
214
+ if pending:
215
+ loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
216
+ except Exception:
217
+ pass
218
+ finally:
219
+ loop.close()
220
+ except Exception as e:
221
+ log.error(f"Event loop error scanning {ip}:{port}: {e}")
222
+ return "Unknown"
@@ -21,6 +21,20 @@ def get_port_lists():
21
21
  return jsonify(PortManager().get_port_lists())
22
22
 
23
23
 
24
+ @api_bp.route('/api/port/list/summary', methods=['GET'])
25
+ def get_port_lists_summary():
26
+ """Get port list names with their port counts."""
27
+ manager = PortManager()
28
+ summaries = []
29
+ for name in manager.get_port_lists():
30
+ ports = manager.get_port_list(name) or {}
31
+ summaries.append({
32
+ 'name': name,
33
+ 'count': len(ports)
34
+ })
35
+ return jsonify(summaries)
36
+
37
+
24
38
  @api_bp.route('/api/port/list/<port_list>', methods=['GET'])
25
39
  def get_port_list(port_list):
26
40
  """
@@ -66,13 +66,16 @@ body:has(.submodule) footer {
66
66
 
67
67
  #header {
68
68
  background-color: var(--primary-bg);
69
- padding: 8px 20px;
69
+ padding: 8px 2%;
70
70
  margin: 0;
71
71
  display: block;
72
72
  position: relative;
73
73
  box-shadow: 0 0 10px var(--box-shadow);
74
74
  width: 100vw;
75
75
  }
76
+ #header .title {
77
+ font-size: 36px;
78
+ }
76
79
 
77
80
  footer {
78
81
  position: sticky;
@@ -163,7 +166,12 @@ details {
163
166
 
164
167
 
165
168
  #scan-form {
166
- width: 500px;
169
+ width: 60vw;
170
+ margin: 0;
171
+ min-width: 300px;
172
+ max-width: 700px;
173
+ }
174
+ #scan-form .form-group {
167
175
  margin: 0;
168
176
  }
169
177
  #scan-form label {
@@ -304,6 +312,9 @@ details {
304
312
  }
305
313
  #advanced-modal label {
306
314
  font-size: 12px;
315
+ text-overflow: ellipsis;
316
+ overflow: hidden;
317
+ white-space: nowrap;
307
318
  }
308
319
  #advanced-modal .form-check {
309
320
  width: fit-content;
@@ -447,8 +458,10 @@ button {
447
458
 
448
459
  #scan-form #scan-submit {
449
460
  border: none;
450
- padding: 10px 20px;
451
- margin-top: 15px;
461
+ padding: 10px 3%;
462
+ margin: 0 15px;
463
+ min-width: 55px;
464
+ height: 42px;
452
465
  }
453
466
 
454
467
  /* Button Styling */
@@ -564,8 +577,8 @@ input[type="range"] {
564
577
  /* Service Strategy Select Styles */
565
578
  .service-strategy-wrapper {
566
579
  position: relative;
567
- display: inline-block;
568
- width: 60%; /* Narrower than port list */
580
+ display: block;
581
+ width: 100%;
569
582
  }
570
583
 
571
584
  .service-strategy {
@@ -657,10 +670,6 @@ input[type="range"] {
657
670
  .table thead tr th.detail-col
658
671
  {
659
672
  width: 30px;
660
- /*
661
- background-color: var(--body-bg);
662
- border: 1px solid var(--text-almost-hidden);
663
- */
664
673
  }
665
674
  .table td:has(.info-icon-container) {
666
675
  width: 30px;
@@ -709,6 +718,12 @@ input[type="range"] {
709
718
  span.alt {
710
719
  color: var(--text-accent-color);
711
720
  }
721
+ span.no-wrap {
722
+ white-space: nowrap;
723
+ overflow: hidden;
724
+ text-overflow: ellipsis;
725
+ display: block;
726
+ }
712
727
  .colorful-buttons a{
713
728
  margin:2px;
714
729
  color: var(--text-color);
@@ -1,10 +1,12 @@
1
1
  $(document).ready(function() {
2
2
  rightSizeDocLayout(0,showFooter);
3
3
  initTooltips();
4
+ adjustNoWrap();
4
5
  })
5
6
 
6
7
  $(window).on('resize', function() {
7
8
  rightSizeDocLayout();
9
+ adjustNoWrap();
8
10
  });
9
11
 
10
12
 
@@ -36,4 +38,16 @@ function initTooltips() {
36
38
  tooltipTriggerList.map(function (tooltipTriggerEl) {
37
39
  return new bootstrap.Tooltip(tooltipTriggerEl)
38
40
  })
41
+ }
42
+
43
+ /*
44
+ An imperfect approach to adjusting
45
+ text field width within a table
46
+ */
47
+ function adjustNoWrap() {
48
+ $('.no-wrap').width(0);
49
+ $('.no-wrap').each(function() {
50
+ var parentWidth = $(this).parent().width();
51
+ $(this).width(parseInt(parentWidth));
52
+ });
39
53
  }
@@ -8,6 +8,9 @@ function quietReload() {
8
8
  var newDoc = new DOMParser().parseFromString(data, 'text/html');
9
9
  // replace current body with the new body content
10
10
  $('body').html($(newDoc.body).html());
11
+ if (typeof adjustNoWrap === 'function') {
12
+ adjustNoWrap();
13
+ }
11
14
  });
12
15
  }
13
16
  setTimeout(function() {
@@ -139,15 +139,26 @@ function getScanConfig() {
139
139
  }
140
140
 
141
141
  function getPortLists(callback=null) {
142
- $.get('/api/port/list', function(data) {
143
- const customSelectDropdown = $('#port_list');
142
+ const customSelectDropdown = $('#port_list');
143
+
144
+ const renderOptions = (items) => {
144
145
  customSelectDropdown.empty();
145
-
146
- // Populate the dropdown with the options
147
- data.forEach(function(portList) {
148
- customSelectDropdown.append('<option>' + portList + '</option>');
146
+ items.forEach((item) => {
147
+ const name = item.name || item;
148
+ const count = item.count;
149
+ const label = count !== undefined ? `${name} (${count} ports)` : name;
150
+ customSelectDropdown.append(`<option value="${name}">${label}</option>`);
149
151
  });
152
+ };
153
+
154
+ $.get('/api/port/list/summary', function(data) {
155
+ renderOptions(data || []);
150
156
  if (callback) callback();
157
+ }).fail(function() {
158
+ $.get('/api/port/list', function(data) {
159
+ renderOptions(data || []);
160
+ if (callback) callback();
161
+ });
151
162
  });
152
163
  }
153
164
 
@@ -3,45 +3,43 @@
3
3
  {% block content %}
4
4
  <div id="header">
5
5
  <!-- Header and Scan Submission Inline -->
6
- <div class="d-flex justify-content-between align-items-center flex-nowrap">
6
+ <div class="d-flex justify-content-between align-items-center flex-wrap">
7
7
  <a href="/" class="text-decoration-none" aria-label="Go to homepage">
8
8
  <h1 class="title">
9
9
  <span>LAN</span>scape
10
10
  </h1>
11
11
  </a>
12
12
  <!-- Right side: settings + form -->
13
- <div class="d-flex align-items-center justify-content-end ms-auto">
14
- <form id="scan-form" class="d-flex align-items-center">
15
- <div class="form-group me-2">
16
- <!-- Above subnet input -->
17
- <div class="label-container">
18
- <label for="subnet">Subnet:</label>
19
- <div id="subnet-info"></div>
20
- </div>
21
- <!-- Subnet input with dropdown -->
22
- <div class="input-group">
23
- <button
24
- type="button"
25
- id="settings-btn"
26
- class="btn btn-secondary start"
27
- data-bs-toggle="tooltip"
28
- data-bs-placement="bottom"
29
- title="Advanced scan settings"
30
- >
31
- <i class="fa-solid fa-gear"></i>
32
- </button>
33
- <input type="text" id="subnet" name="subnet" class="form-control" value="{{ subnet }}" placeholder="Enter subnet">
34
- <button class="btn btn-secondary dropdown-toggle end" type="button" id="subnet-dropdown" data-bs-toggle="dropdown" aria-expanded="false"></button>
35
- <ul class="dropdown-menu" aria-labelledby="subnet-dropdown" id="dropdown-list">
36
- {% for subnet_option in alternate_subnets %}
37
- <li><a class="dropdown-item" href="#">{{ subnet_option['subnet'] }}</a></li>
38
- {% endfor %}
39
- </ul>
40
- </div>
13
+ <form id="scan-form" class="d-flex align-items-end">
14
+ <div class="form-group me-2">
15
+ <!-- Above subnet input -->
16
+ <div class="label-container">
17
+ <label for="subnet">Subnet:</label>
18
+ <div id="subnet-info"></div>
41
19
  </div>
42
- <button type="submit" id="scan-submit" class="btn btn-primary">Scan</button>
43
- </form>
44
- </div>
20
+ <!-- Subnet input with dropdown -->
21
+ <div class="input-group">
22
+ <button
23
+ type="button"
24
+ id="settings-btn"
25
+ class="btn btn-secondary start"
26
+ data-bs-toggle="tooltip"
27
+ data-bs-placement="bottom"
28
+ title="Advanced scan settings"
29
+ >
30
+ <i class="fa-solid fa-gear"></i>
31
+ </button>
32
+ <input type="text" id="subnet" name="subnet" class="form-control" value="{{ subnet }}" placeholder="Enter subnet">
33
+ <button class="btn btn-secondary dropdown-toggle end" type="button" id="subnet-dropdown" data-bs-toggle="dropdown" aria-expanded="false"></button>
34
+ <ul class="dropdown-menu" aria-labelledby="subnet-dropdown" id="dropdown-list">
35
+ {% for subnet_option in alternate_subnets %}
36
+ <li><a class="dropdown-item" href="#">{{ subnet_option['subnet'] }}</a></li>
37
+ {% endfor %}
38
+ </ul>
39
+ </div>
40
+ </div>
41
+ <button type="submit" id="scan-submit" class="btn btn-primary">Scan</button>
42
+ </form>
45
43
  </div>
46
44
 
47
45
  <div id="scan-progress-bar"></div>
@@ -94,7 +94,7 @@
94
94
  </div>
95
95
  <div class="col-1 descriptor">=</div>
96
96
  <div class="col-3">
97
- <label for="total-ping-attempts">Max pings per device</label>
97
+ <label for="total-ping-attempts" id="tpa-label">Max pings per device</label>
98
98
  <input type="number" id="total-ping-attempts" class="form-control" readonly>
99
99
  </div>
100
100
  </div>
@@ -201,7 +201,7 @@
201
201
  <div id="section-service-scan" class="form-group mt-2 config-section div-hide">
202
202
  <h6>Service Scanning</h6>
203
203
  <div class="row">
204
- <div class="col">
204
+ <div class="col-12">
205
205
  <label for="service_lookup_type" class="form-label">Strategy</label>
206
206
  <div class="service-strategy-wrapper">
207
207
  <select id="service_lookup_type" class="service-strategy">
@@ -211,11 +211,13 @@
211
211
  </select>
212
212
  </div>
213
213
  </div>
214
- <div class="col">
214
+ </div>
215
+ <div class="row mt-2">
216
+ <div class="col-12 col-md-6">
215
217
  <label for="service_timeout" class="form-label">Timeout (sec)</label>
216
218
  <input type="number" step="0.1" id="service_timeout" class="form-control">
217
219
  </div>
218
- <div class="col">
220
+ <div class="col-12 col-md-6 mt-2 mt-md-0">
219
221
  <label for="service_max_concurrent_probes" class="form-label">Max Concurrent Probes</label>
220
222
  <input type="number" id="service_max_concurrent_probes" class="form-control">
221
223
  </div>
@@ -7,20 +7,20 @@
7
7
  ></i>
8
8
  </div>
9
9
  </td>
10
- <td>
10
+ <td class="ip">
11
11
  <div>{{ device.ip }}</div>
12
12
  {% if device.hostname %}
13
- <div><span class=alt>{{device.hostname}}</span></div>
13
+ <span class="alt no-wrap">{{device.hostname}}</span>
14
14
  {% endif %}
15
15
  </td>
16
- <td>
16
+ <td class="mac">
17
17
  <div>{{ device.mac_addr or 'Unknown' }}</div>
18
18
  {% if device.manufacturer %}
19
- <div><span class="alt">{{device.manufacturer}}</span></div>
19
+ <span class="alt no-wrap">{{device.manufacturer}}</span>
20
20
  {% endif %}
21
21
  </td>
22
- <td>{{ device.ports | join(", ") }}</td>
23
- <td>
22
+ <td class="ports">{{ device.ports | join(", ") }}</td>
23
+ <td class="stage">
24
24
  {% if device.stage == 'complete' %}
25
25
  <span class="badge badge-success">complete</span>
26
26
  {% elif device.stage == 'found' %}
@@ -9,10 +9,10 @@
9
9
  <thead>
10
10
  <tr>
11
11
  <th class="detail-col" scope="col"></th>
12
- <th scope="col">IP / <span class="alt">Host</span></th>
13
- <th scope="col">MAC / <span class="alt">Manufacturer</span></th>
14
- <th scope="col">Open Ports</th>
15
- <th scope="col">Stage</th>
12
+ <th class="ip" scope="col">IP / <span class="alt">Host</span></th>
13
+ <th class="mac" scope="col">MAC / <span class="alt">Manufacturer</span></th>
14
+ <th class="ports" scope="col">Open Ports</th>
15
+ <th class="stage" scope="col">Stage</th>
16
16
  </tr>
17
17
  </thead>
18
18
  <tbody>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lanscape
3
- Version: 2.2.1a1
3
+ Version: 2.3.1
4
4
  Summary: A python based local network scanner
5
5
  Author-email: Michael Dennis <michael@dipduo.com>
6
6
  License-Expression: MIT
@@ -31,6 +31,8 @@ Requires-Dist: pytest>=8.0; extra == "dev"
31
31
  Requires-Dist: pytest-cov>=5.0; extra == "dev"
32
32
  Requires-Dist: pytest-xdist>=3.0; extra == "dev"
33
33
  Requires-Dist: openai>=1.0.0; extra == "dev"
34
+ Requires-Dist: pylint>=3.0; extra == "dev"
35
+ Requires-Dist: autopep8>=2.0; extra == "dev"
34
36
  Dynamic: license-file
35
37
 
36
38
  # LANscape
@@ -8,11 +8,11 @@ lanscape/core/errors.py,sha256=QTf42UzR9Zxj1t1mdwfLvZIp0c9a5EItELOdCR7kTmE,1322
8
8
  lanscape/core/ip_parser.py,sha256=kn5H4ERitLnreRAqifWphwbxdjItGqwu50lsMCPDMcA,3474
9
9
  lanscape/core/logger.py,sha256=nzo6J8UdlMdhRkOJEDOIHKztoE3Du8PQZad7ixvNgeM,2534
10
10
  lanscape/core/mac_lookup.py,sha256=PxBSMe3wEVDtivCsh5NclSAguZz9rqdAS7QshBiuWvM,3519
11
- lanscape/core/net_tools.py,sha256=Ht8TkLnKf-f6E1_AkTCde-yuiwUNI57TCXke0nIFi0o,21303
11
+ lanscape/core/net_tools.py,sha256=PsyH-I6ylrkJaVas_YUttYPhU2Cs8I5uCLibPzXxuoM,22076
12
12
  lanscape/core/port_manager.py,sha256=3_ROOb6JEiB0NByZVtADuGcldFkgZwn1RKtvwgs9AIk,4479
13
13
  lanscape/core/runtime_args.py,sha256=2vIqRrcWr-NHRSBlZGrxh1PdkPY0ytkPguu8KZqy2L8,2543
14
14
  lanscape/core/scan_config.py,sha256=A2ZKXqXKW9nrP6yLb7b9b3XqSY_cQB3LZ5K0LVCSebE,11114
15
- lanscape/core/service_scan.py,sha256=wTDxOdazOsbI0hwCBR__4UCmB2RIbl2pw3F2YUW9aaE,6428
15
+ lanscape/core/service_scan.py,sha256=umDVOoCNNVJhWMtxDV-rn7hcS7t_V073srSMPTl5gMo,7943
16
16
  lanscape/core/subnet_scan.py,sha256=PtSOk92dK05-reyr8LBkOXaI15qpYnar5nDqALCX1tQ,14850
17
17
  lanscape/core/version_manager.py,sha256=eGjyKgsv31QO0W26se9pPQ1TwmEN8qn37dHULtoocqc,2841
18
18
  lanscape/resources/mac_addresses/convert_csv.py,sha256=hvlyLs0XmuuhBuvXBNRGP1cKJzYVRSf8VfUJ1VqROms,1189
@@ -30,13 +30,13 @@ lanscape/ui/main.py,sha256=KXVPfHbKbMP2mMvJ3e2nqdmMTbTadEfuZ7tP4SIDIqE,4334
30
30
  lanscape/ui/shutdown_handler.py,sha256=HrEnWrdYSzLDVsPgD8tf9FgtAwQrZNECDu6wnEs27EY,1704
31
31
  lanscape/ui/blueprints/__init__.py,sha256=EjPtaR5Nh17pGiOVYTJULVNaZntpFZOiYyep8rBWAiE,265
32
32
  lanscape/ui/blueprints/api/__init__.py,sha256=5Z4Y7B36O-bNFenpomfuNhPuJ9dW_MC0TPUU3pCFVfA,103
33
- lanscape/ui/blueprints/api/port.py,sha256=KlfLrAmlTqN44I1jLVDy-mWOcor4kL-b0Cl4AcTMCys,1976
33
+ lanscape/ui/blueprints/api/port.py,sha256=enqJ87hpVHSTBoaV9bJ7IgsvHrWDTga704wV33dtwUg,2384
34
34
  lanscape/ui/blueprints/api/scan.py,sha256=2rsW4xkI4X2Q2ocwaE469aU1VxQ3xHuBRjD9xE36WdI,3326
35
35
  lanscape/ui/blueprints/api/tools.py,sha256=jr9gt0VhvBFgJ61MLgNIM6hin-MUmJLGdmStPx3e3Yc,2432
36
36
  lanscape/ui/blueprints/web/__init__.py,sha256=NvgnjP0X4LwqVhSEyh5RUzoG45N44kHK1MEFlfvBxTg,118
37
37
  lanscape/ui/blueprints/web/routes.py,sha256=f5TzfTzelJ_erslyBXTOpFr4BlIfB1Mb1ye6ioH7IL0,4534
38
38
  lanscape/ui/static/lanscape.webmanifest,sha256=07CqA-PQsO35KJD8R96sI3Pxix6UuBjijPDCuy9vM3s,446
39
- lanscape/ui/static/css/style.css,sha256=9IQru_W0WUpcxNJuHbqwjfxLOC5n1EeGcxf_kDVY3jc,21232
39
+ lanscape/ui/static/css/style.css,sha256=UWu0fOCVhNKRtKawaCy4hp-dU5Q-ac2WiSdIwRQMvFs,21442
40
40
  lanscape/ui/static/img/ico/android-chrome-192x192.png,sha256=JmFT6KBCCuoyxMV-mLNtF9_QJbVBvfWPUizKN700fi8,18255
41
41
  lanscape/ui/static/img/ico/android-chrome-512x512.png,sha256=88Jjx_1-4XAnZYz64KP6FdTl_kYkNG2_kQIKteQwSh4,138055
42
42
  lanscape/ui/static/img/ico/apple-touch-icon.png,sha256=tEJlLwBZtF4v-NC90YCfRJQ2prTsF4i3VQLK_hnv2Mw,16523
@@ -44,33 +44,33 @@ lanscape/ui/static/img/ico/favicon-16x16.png,sha256=HpQOZk3rziZjT1xQxKuy5WourXsf
44
44
  lanscape/ui/static/img/ico/favicon-32x32.png,sha256=UpgiDPIHckK19udHtACiaI3ZPbmImUUcN1GcrjpEg9s,1302
45
45
  lanscape/ui/static/img/ico/favicon.ico,sha256=rs5vq0MPJ1LzzioOzOz5aQLVfrtS2nLRc920dOeReTw,15406
46
46
  lanscape/ui/static/img/ico/site.webmanifest,sha256=ep4Hzh9zhmiZF2At3Fp1dQrYQuYF_3ZPZxc1KcGBvwQ,263
47
- lanscape/ui/static/js/core.js,sha256=J37LcjchyiNirSkicraoWr-TsW2QeQX_zUwo5mGMmoM,1073
47
+ lanscape/ui/static/js/core.js,sha256=TzyoD1NCnIY-2JLArymw0JoMOq0CMeJrZDmZyMdMK2I,1394
48
48
  lanscape/ui/static/js/layout-sizing.js,sha256=U2dsyJi-YKpOpudu3kg2whiU4047ghzDTY3ExYUhpPs,810
49
49
  lanscape/ui/static/js/main.js,sha256=Bgb5Ld_UPWzBVzxWkLD0kJGjOoLJyzni2TKE6Uk99VA,7428
50
50
  lanscape/ui/static/js/on-tab-close.js,sha256=3icxYWlLpY81iLoW7kQTJeWQ3UnyyboG0dESHF2wLPQ,1376
51
- lanscape/ui/static/js/quietReload.js,sha256=8POH0t1KVzGCJas9fNsOVbBG-ULwZT2wiS14URgkeAU,702
52
- lanscape/ui/static/js/scan-config.js,sha256=TiUwWWUGqqQbC3ZJnQCNQpoR492RXA3jLkALe6Nzl5Q,7726
51
+ lanscape/ui/static/js/quietReload.js,sha256=T7lvxVejMGJr1cKdABedyiaTVukZfRDIKV7Eyv-jeyc,802
52
+ lanscape/ui/static/js/scan-config.js,sha256=nQ2dWkgpf8yer-lCMTZ25DBqOuWt0SIyzzfdP_fS-bE,8086
53
53
  lanscape/ui/static/js/shutdown-server.js,sha256=Mx8UGmmktHaCK7DL8TVUxah6VEcN0wwLFfhbCId-K8U,453
54
54
  lanscape/ui/static/js/subnet-info.js,sha256=osZM6CGs-TC5QpBJWkNWCtXNOKzjyIiWKHwKi4vlDf8,559
55
55
  lanscape/ui/static/js/subnet-selector.js,sha256=2YKCAuKU2Ti1CmJrqi4_vNTD2LQbxx7chIDqND_1eAY,358
56
56
  lanscape/ui/templates/base.html,sha256=HIHLFEUMDTGEaeuSpeNg-vkXXb9VNbZnbFWlYetVL18,1377
57
57
  lanscape/ui/templates/error.html,sha256=bqGJbf_ix9wtpUlXk5zvz_XyFpeTbEO-4f0ImgLtUGk,1033
58
58
  lanscape/ui/templates/info.html,sha256=SQ6RpTs9_v9HF32mr3FBsh6vTJneYqFz_WrC9diXzHg,2958
59
- lanscape/ui/templates/main.html,sha256=jTFLH9xuMNayQRkDNB_8BIQopaD4YtI5MI2zMpaMsMA,3842
59
+ lanscape/ui/templates/main.html,sha256=CVBwJCNBjzOTFDCiIicT1wuptjCUfZzMc7YSvu4OXxA,3626
60
60
  lanscape/ui/templates/scan.html,sha256=00QX2_1S_1wGzk42r00LjEkJvoioCLs6JgjOibi6r20,376
61
61
  lanscape/ui/templates/shutdown.html,sha256=iXVCq2yl5TjZfNFl4esbDJra3gJA2VQpae0jj4ipy9w,701
62
62
  lanscape/ui/templates/core/head.html,sha256=zP1RkTYuaKCC6RtnSEHFKPw3wKWfSyV0HZg5XsAxWik,719
63
63
  lanscape/ui/templates/core/scripts.html,sha256=rSRi4Ut8iejajMPhOc5bzEz-Z3EHxpj_3PxwwyyhmTQ,640
64
- lanscape/ui/templates/scan/config.html,sha256=X95xayNtJrRUeGUlPbtUjd1228hH6re9BT6jcbaSnl8,14704
64
+ lanscape/ui/templates/scan/config.html,sha256=vI5ZuJLZE5FwbTRkQyXwIRP-bwe_cZdSyzDZVZu1s_w,14821
65
65
  lanscape/ui/templates/scan/device-detail.html,sha256=3N0WcdnWopbSFwsnKogBaHOYsLMAfKBZdkP7HQG4vLA,4794
66
66
  lanscape/ui/templates/scan/export.html,sha256=Nvs_unojzT3qhN_ZnEgYHou2C9wqWGr3dVr2UiLnYjY,749
67
- lanscape/ui/templates/scan/ip-table-row.html,sha256=iSW3PYev3_k7pxTZUJUboqDUgdhsWNOrYxysYismyI0,1255
68
- lanscape/ui/templates/scan/ip-table.html,sha256=AT2ZvCPYdKl-XJiAkEAawPOVuQw-w0MXumGQTr3zyKM,926
67
+ lanscape/ui/templates/scan/ip-table-row.html,sha256=viAvjJcye3jYpDsWGR2To8BGqr1NxuF3gPO2ECQnxUU,1302
68
+ lanscape/ui/templates/scan/ip-table.html,sha256=8pkaStlVeGJ3h6spk8eKu3Ft5HffH7KpHD3vjECyHa0,977
69
69
  lanscape/ui/templates/scan/overview.html,sha256=xWj9jWDPg2KcPLvS8fnSins23_UXjKCdb2NJwNG2U2Q,1176
70
70
  lanscape/ui/templates/scan/scan-error.html,sha256=wmAYQ13IJHUoO8fAGNDjMvNml7tu4rsIU3Vav71ETlA,999
71
- lanscape-2.2.1a1.dist-info/licenses/LICENSE,sha256=VLoE0IrNTIc09dFm7hMN0qzk4T3q8V0NaPcFQqMemDs,1070
72
- lanscape-2.2.1a1.dist-info/METADATA,sha256=INz2lnO8UO83zXGFZZhF7Ghz2tHM0iqMjYNOKiDvWPU,3615
73
- lanscape-2.2.1a1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
- lanscape-2.2.1a1.dist-info/entry_points.txt,sha256=evxSxUikFa1OEd4e0Boky9sLH87HdgM0YqB_AbB2HYc,51
75
- lanscape-2.2.1a1.dist-info/top_level.txt,sha256=E9D4sjPz_6H7c85Ycy_pOS2xuv1Wm-ilKhxEprln2ps,9
76
- lanscape-2.2.1a1.dist-info/RECORD,,
71
+ lanscape-2.3.1.dist-info/licenses/LICENSE,sha256=VLoE0IrNTIc09dFm7hMN0qzk4T3q8V0NaPcFQqMemDs,1070
72
+ lanscape-2.3.1.dist-info/METADATA,sha256=DogrRb50_kIcDrJgTlgxLNCP2YfsrJite_57I9_fOhY,3701
73
+ lanscape-2.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
+ lanscape-2.3.1.dist-info/entry_points.txt,sha256=evxSxUikFa1OEd4e0Boky9sLH87HdgM0YqB_AbB2HYc,51
75
+ lanscape-2.3.1.dist-info/top_level.txt,sha256=E9D4sjPz_6H7c85Ycy_pOS2xuv1Wm-ilKhxEprln2ps,9
76
+ lanscape-2.3.1.dist-info/RECORD,,