dapps 0.3.0__tar.gz → 0.3.1__tar.gz
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.
- {dapps-0.3.0 → dapps-0.3.1}/PKG-INFO +1 -1
- dapps-0.3.1/VERSION +1 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/e3_interface.py +21 -2
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/libe3_agent.py +4 -3
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/policy.py +5 -4
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/spectrum_dapp.py +7 -7
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_latrec_stamps.py +2 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_outbound_send_result.py +1 -1
- dapps-0.3.1/tests/test_report_sequence_id.py +51 -0
- dapps-0.3.0/VERSION +0 -1
- {dapps-0.3.0 → dapps-0.3.1}/.github/CODEOWNERS +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/new_sm.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/workflows/mirror.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/workflows/tag-and-release.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.github/workflows/test.yml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/.gitignore +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/CMakeLists.txt +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/CONTRIBUTING.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/CONTRIBUTORS +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/LICENSE +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/MANIFEST.in +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/README.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/SECURITY.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/docs/dapp_uml.txt +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/docs/ground_truth_labeling.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/docs/gui_uml.txt +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/examples/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/examples/hackathon_policy.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/examples/simple_dapp.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/examples/spectrum_dapp.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/CMakeLists.txt +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/cmake/libiqsaver.pc.in +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/cmake/libiqsaverConfig.cmake.in +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/include/iqsaver/annotation.hpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/include/iqsaver/iq_saver_writer.hpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/include/iqsaver/iqsaver.hpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/include/iqsaver/types.hpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/include/iqsaver/version.hpp.in +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/src/iq_saver_writer.cpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/swig/iqsaver.i +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/swig/iqsaver_swig.cpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/libiqsaver/swig/iqsaver_swig.hpp +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/pyproject.toml +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/dapp/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/dapp/control_server.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/dapp/dapp.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/e3_logging.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/e3_transport.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/latrec.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/e3interface/sm_helpers.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/iq_saver/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/iq_saver/iq_saver.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/simple/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/simple/defs/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/simple/defs/e3sm_simple.proto +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/simple/defs/e3sm_simple_pb2.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/simple/simple_dapp.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/README.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/adaptive_noise_floor.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/control_handlers.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_oai_l1_kpm.asn +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_oai_l1_kpm.proto +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_oai_l1_kpm_pb2.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_spectrum.asn +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_spectrum.json +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_spectrum.proto +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/defs/e3sm_spectrum_pb2.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/e3_l2_sensing_reader.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/e3_ran_buffers_reader.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/embargo_manager.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/ru_profiles.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/slot_recorder.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/spectrum/threshold_detector.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/__init__.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/energy.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/grafana.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/influx.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/iq.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/subcarrier/insi_white.png +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/subcarrier/start_subcarrier_visualizer.sh +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/subcarrier/subcarrier_visualizer.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/src/visualization/subcarrier_pub.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/start_dapp.sh +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_control_handlers.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_control_server.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_detector_configure.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_detector_granularity_pipeline.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_e3_concurrency.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_indication_dispatch.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_iq_saver.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_latrec.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_libe3_agent.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_policy.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_protobuf_sm.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_ru_profiles.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_sensing_policy.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_spectrum_sm_timestamps_mask.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_spectrum_telemetry.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_subcarrier_pub_viz.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tests/test_visualizer_grid.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tools/README.md +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tools/asntojson.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tools/generate_sm.sh +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tools/read_recording.py +0 -0
- {dapps-0.3.0 → dapps-0.3.1}/tools/regen_proto.sh +0 -0
dapps-0.3.1/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.1
|
|
@@ -90,6 +90,9 @@ class E3Interface:
|
|
|
90
90
|
# Guards the three callback dicts above: caller-thread add_/remove_*
|
|
91
91
|
# vs. inbound-thread iteration in the _handle_* dispatchers.
|
|
92
92
|
self._callback_lock = threading.Lock()
|
|
93
|
+
# Source of the report correlation ids (see schedule_report).
|
|
94
|
+
self._report_seq = 0
|
|
95
|
+
self._report_seq_lock = threading.Lock()
|
|
93
96
|
self.stop_event = threading.Event()
|
|
94
97
|
# Subscription-response correlation. The wire is fire-and-forget, so a
|
|
95
98
|
# queued request is NOT an accepted one — a queue put() succeeding
|
|
@@ -336,7 +339,7 @@ class E3Interface:
|
|
|
336
339
|
case "report":
|
|
337
340
|
rc = self.agent.send_report(
|
|
338
341
|
data["ranFunctionId"], data["reportData"],
|
|
339
|
-
data
|
|
342
|
+
data["sequenceId"])
|
|
340
343
|
case "release":
|
|
341
344
|
rc = self.agent.release()
|
|
342
345
|
case _:
|
|
@@ -467,12 +470,28 @@ class E3Interface:
|
|
|
467
470
|
'latSeq': latrec.ctx(),
|
|
468
471
|
}))
|
|
469
472
|
|
|
470
|
-
def
|
|
473
|
+
def _next_report_sequence_id(self) -> int:
|
|
474
|
+
"""Next correlation id for a report: 1..4294967295, wrapping to 1 (0 is not a valid id)."""
|
|
475
|
+
with self._report_seq_lock:
|
|
476
|
+
self._report_seq = self._report_seq % 0xFFFFFFFF + 1
|
|
477
|
+
return self._report_seq
|
|
478
|
+
|
|
479
|
+
def schedule_report(self, dappId: int, ranFunctionId: int, reportData: bytes,
|
|
480
|
+
sequenceId: int = 0) -> int:
|
|
481
|
+
"""Queue a report and return its correlation id.
|
|
482
|
+
|
|
483
|
+
The id is mandatory on the wire (E3-SequenceID, 1..4294967295) and travels on to the
|
|
484
|
+
xApp. Pass the one you want, or leave it at 0 to get the next one from this interface.
|
|
485
|
+
"""
|
|
486
|
+
if not sequenceId:
|
|
487
|
+
sequenceId = self._next_report_sequence_id()
|
|
471
488
|
self.outbound_queue.put(('report', {
|
|
472
489
|
'ranFunctionId': ranFunctionId,
|
|
473
490
|
'reportData': reportData,
|
|
491
|
+
'sequenceId': sequenceId,
|
|
474
492
|
'latSeq': latrec.ctx(),
|
|
475
493
|
}))
|
|
494
|
+
return sequenceId
|
|
476
495
|
|
|
477
496
|
def add_subscription_callback(self, dapp_id: int, callback):
|
|
478
497
|
with self._callback_lock:
|
|
@@ -247,7 +247,7 @@ class Libe3Agent:
|
|
|
247
247
|
) -> int:
|
|
248
248
|
"""Send a subscribe request.
|
|
249
249
|
|
|
250
|
-
Returns the assigned request id (a positive int
|
|
250
|
+
Returns the assigned request id (a positive int) on success —
|
|
251
251
|
so the caller can correlate the SubscriptionResponse (which echoes
|
|
252
252
|
``request_id``) back to this call — or a negative libe3 ErrorCode on
|
|
253
253
|
failure.
|
|
@@ -275,11 +275,12 @@ class Libe3Agent:
|
|
|
275
275
|
return self._session.send_control(int(ran_function_id), int(control_id), bytes(action_data),
|
|
276
276
|
int(sequence_id))
|
|
277
277
|
|
|
278
|
-
def send_report(self, ran_function_id: int, report_data: bytes, sequence_id: int
|
|
278
|
+
def send_report(self, ran_function_id: int, report_data: bytes, sequence_id: int) -> int:
|
|
279
279
|
"""Send a report to the RAN.
|
|
280
280
|
|
|
281
281
|
``sequence_id`` is the correlation id this dApp assigns to the detection;
|
|
282
|
-
it travels to the xApp on the resulting E2 indication.
|
|
282
|
+
it travels to the xApp on the resulting E2 indication. It is mandatory on the
|
|
283
|
+
wire (1..4294967295); 0 is not valid and is refused with a negative ErrorCode.
|
|
283
284
|
"""
|
|
284
285
|
return self._session.send_report(int(ran_function_id), bytes(report_data), int(sequence_id))
|
|
285
286
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
A policy decides which PRBs the gNB must stop using. The dApp feeds it one
|
|
4
4
|
:class:`Observation` per detector run and sends the PRB blacklist it returns.
|
|
5
5
|
Everything else (E3 connection, subscriptions, DC-leakage guard, control
|
|
6
|
-
reconciliation
|
|
6
|
+
reconciliation, which sends a control only when the set changed) stays in
|
|
7
|
+
:class:`spectrum.spectrum_dapp.SpectrumSharingDApp`.
|
|
7
8
|
|
|
8
9
|
Write a policy by subclassing :class:`Policy`::
|
|
9
10
|
|
|
@@ -62,9 +63,9 @@ class Observation:
|
|
|
62
63
|
class Policy(ABC):
|
|
63
64
|
"""Base class of a PRB-blocking policy.
|
|
64
65
|
|
|
65
|
-
The dApp calls :meth:`update` once per observation (
|
|
66
|
-
|
|
67
|
-
not returned are released. State between calls lives on ``self``;
|
|
66
|
+
The dApp calls :meth:`update` once per observation (every few milliseconds, about
|
|
67
|
+
6.7 ms nominal, depending on how fast the gNB runs). It returns the set of PRB
|
|
68
|
+
indices to block; PRBs that are not returned are released. State between calls lives on ``self``;
|
|
68
69
|
``self.history`` holds the last ``history_len`` observations, the current one last.
|
|
69
70
|
"""
|
|
70
71
|
|
|
@@ -755,11 +755,11 @@ class SpectrumSharingDApp(DApp):
|
|
|
755
755
|
Spectrum-DAppControlData envelope.
|
|
756
756
|
|
|
757
757
|
Drives the gNB's per-MAC prb_block_state_t via set_prb_block_mask():
|
|
758
|
-
each PRB in ``blocked_prbs`` gets every UL symbol marked occupied
|
|
759
|
-
|
|
758
|
+
each PRB in ``blocked_prbs`` gets every UL symbol marked occupied and is
|
|
759
|
+
withheld from DL scheduling too, so the gNB uses it in neither direction.
|
|
760
760
|
|
|
761
761
|
Args:
|
|
762
|
-
blocked_prbs: List of PRB indices to block
|
|
762
|
+
blocked_prbs: List of PRB indices to block (UL and DL)
|
|
763
763
|
update_sampling: Whether to include the updated sampling threshold
|
|
764
764
|
validity_period: How long this block is valid in seconds (optional)
|
|
765
765
|
|
|
@@ -1747,10 +1747,10 @@ class SpectrumSharingDApp(DApp):
|
|
|
1747
1747
|
# mask-of-slot-N applied to IQ-of-slot-N+k → UE energy bleeding
|
|
1748
1748
|
# into "sensing" cells.
|
|
1749
1749
|
#
|
|
1750
|
-
#
|
|
1751
|
-
# slots ×
|
|
1752
|
-
#
|
|
1753
|
-
# untrustworthy and skip the slot.
|
|
1750
|
+
# The bound comes from the ring depth in the shm header (see
|
|
1751
|
+
# _shm_staleness_ns): 16 rows × 2 buffers = 32 slots × 0.5 ms/slot at
|
|
1752
|
+
# 30 kHz SCS = 16 ms. Until the header is read a fixed 50 ms is used.
|
|
1753
|
+
# If breached, treat the IQ as untrustworthy and skip the slot.
|
|
1754
1754
|
if p.timestamp_ns > 0:
|
|
1755
1755
|
lag_ns = t.recv_ns - p.timestamp_ns
|
|
1756
1756
|
stale_ns = self._shm_staleness_ns()
|
|
@@ -47,6 +47,8 @@ def _iface():
|
|
|
47
47
|
iface.subscription_callbacks = {}
|
|
48
48
|
iface.xapp_control_callbacks = {}
|
|
49
49
|
iface._callback_lock = threading.Lock()
|
|
50
|
+
iface._report_seq = 0
|
|
51
|
+
iface._report_seq_lock = threading.Lock()
|
|
50
52
|
iface.stop_event = threading.Event()
|
|
51
53
|
iface.outbound_queue = queue.Queue()
|
|
52
54
|
return iface
|
|
@@ -42,7 +42,7 @@ def _drain(rc, msg, data, caplog):
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
CONTROL = {"ranFunctionId": 1, "controlId": 1, "actionData": b"x"}
|
|
45
|
-
REPORT = {"ranFunctionId": 1, "reportData": b"x"}
|
|
45
|
+
REPORT = {"ranFunctionId": 1, "reportData": b"x", "sequenceId": 1}
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
@pytest.mark.parametrize("msg,data", [("control", CONTROL), ("report", REPORT)])
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""A report always carries a non-zero correlation id: E3-SequenceID is 1..4294967295 on the wire."""
|
|
2
|
+
import os
|
|
3
|
+
import queue
|
|
4
|
+
import sys
|
|
5
|
+
import threading
|
|
6
|
+
|
|
7
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
8
|
+
|
|
9
|
+
from e3interface.e3_interface import E3Interface
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _iface():
|
|
13
|
+
iface = object.__new__(E3Interface)
|
|
14
|
+
iface.outbound_queue = queue.Queue()
|
|
15
|
+
iface._report_seq = 0
|
|
16
|
+
iface._report_seq_lock = threading.Lock()
|
|
17
|
+
return iface
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_a_report_gets_the_next_non_zero_id():
|
|
21
|
+
iface = _iface()
|
|
22
|
+
ids = [iface.schedule_report(1, 1, b"x") for _ in range(3)]
|
|
23
|
+
assert ids == [1, 2, 3]
|
|
24
|
+
queued = [iface.outbound_queue.get_nowait()[1]["sequenceId"] for _ in range(3)]
|
|
25
|
+
assert queued == ids
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_an_id_given_by_the_caller_is_kept():
|
|
29
|
+
iface = _iface()
|
|
30
|
+
assert iface.schedule_report(1, 1, b"x", sequenceId=77) == 77
|
|
31
|
+
assert iface.outbound_queue.get_nowait()[1]["sequenceId"] == 77
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_the_id_wraps_to_1_and_never_reaches_0():
|
|
35
|
+
iface = _iface()
|
|
36
|
+
iface._report_seq = 0xFFFFFFFE
|
|
37
|
+
assert iface.schedule_report(1, 1, b"x") == 0xFFFFFFFF
|
|
38
|
+
assert iface.schedule_report(1, 1, b"x") == 1
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_ids_are_unique_across_threads():
|
|
42
|
+
iface = _iface()
|
|
43
|
+
out = []
|
|
44
|
+
|
|
45
|
+
def work():
|
|
46
|
+
out.extend(iface.schedule_report(1, 1, b"x") for _ in range(500))
|
|
47
|
+
|
|
48
|
+
threads = [threading.Thread(target=work) for _ in range(4)]
|
|
49
|
+
[t.start() for t in threads]
|
|
50
|
+
[t.join() for t in threads]
|
|
51
|
+
assert len(set(out)) == 2000
|
dapps-0.3.0/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.3.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|