sciveo 0.1.15__tar.gz → 0.1.17__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.
- {sciveo-0.1.15 → sciveo-0.1.17}/PKG-INFO +1 -1
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/__init__.py +1 -1
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/cli.py +1 -1
- sciveo-0.1.17/sciveo/common/tools/compress.py +26 -0
- sciveo-0.1.17/sciveo/common/tools/crypto.py +57 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/daemon.py +17 -0
- sciveo-0.1.17/sciveo/common/tools/random.py +22 -0
- sciveo-0.1.17/sciveo/network/__init__.py +0 -0
- sciveo-0.1.17/sciveo/network/camera.py +63 -0
- sciveo-0.1.15/sciveo/monitoring/network.py → sciveo-0.1.17/sciveo/network/tools.py +57 -1
- sciveo-0.1.17/sciveo/version.py +2 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/PKG-INFO +1 -1
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/SOURCES.txt +8 -1
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/requires.txt +3 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/setup.py +3 -0
- sciveo-0.1.17/test/test_compress.py +16 -0
- sciveo-0.1.17/test/test_crypto.py +34 -0
- sciveo-0.1.15/sciveo/version.py +0 -2
- {sciveo-0.1.15 → sciveo-0.1.17}/README.md +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/api/__init__.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/api/base.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/api/upload.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/__init__.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/configuration.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/model.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/optimizers.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/sampling.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/__init__.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/configuration.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/formating.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/hardware.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/logger.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/synchronized.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/common/tools/timers.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/content/__init__.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/content/dataset.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/content/experiment.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/content/project.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/content/runner.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/monitoring/__init__.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/monitoring/monitor.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo/monitoring/start.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/dependency_links.txt +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/entry_points.txt +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/sciveo.egg-info/top_level.txt +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/setup.cfg +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/test/test_configuration.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/test/test_monitoring.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/test/test_runner.py +0 -0
- {sciveo-0.1.15 → sciveo-0.1.17}/test/test_sampling.py +0 -0
|
@@ -21,7 +21,7 @@ try:
|
|
|
21
21
|
from sciveo.content.runner import ProjectRunner
|
|
22
22
|
from sciveo.content.dataset import Dataset
|
|
23
23
|
from sciveo.monitoring.start import MonitorStart
|
|
24
|
-
from sciveo.
|
|
24
|
+
from sciveo.network.tools import NetworkTools
|
|
25
25
|
from sciveo.version import __version__
|
|
26
26
|
|
|
27
27
|
|
|
@@ -16,7 +16,7 @@ import argparse
|
|
|
16
16
|
from sciveo.common.tools.logger import *
|
|
17
17
|
from sciveo.common.tools.timers import Timer
|
|
18
18
|
from sciveo.monitoring.start import MonitorStart
|
|
19
|
-
from sciveo.
|
|
19
|
+
from sciveo.network.tools import NetworkTools
|
|
20
20
|
from sciveo.common.tools.configuration import GlobalConfiguration
|
|
21
21
|
|
|
22
22
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import gzip
|
|
3
|
+
import base64
|
|
4
|
+
|
|
5
|
+
from sciveo.common.tools.logger import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CompressJsonData:
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def compress(self, data):
|
|
13
|
+
json_data = json.dumps(data).encode('utf-8')
|
|
14
|
+
compressed_data = gzip.compress(json_data)
|
|
15
|
+
encoded_data = base64.b64encode(compressed_data).decode('utf-8')
|
|
16
|
+
debug(type(self).__name__, "compress", len(json_data), "->", len(encoded_data))
|
|
17
|
+
return encoded_data
|
|
18
|
+
|
|
19
|
+
def decompress(self, encoded_data):
|
|
20
|
+
compressed_data = base64.b64decode(encoded_data)
|
|
21
|
+
decompressed_data = gzip.decompress(compressed_data)
|
|
22
|
+
json_data = decompressed_data.decode('utf-8')
|
|
23
|
+
data = json.loads(json_data)
|
|
24
|
+
debug(type(self).__name__, "decompress", len(encoded_data), "->", len(json_data))
|
|
25
|
+
return data
|
|
26
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import base64
|
|
3
|
+
from Crypto.Cipher import AES
|
|
4
|
+
from Crypto.Random import get_random_bytes
|
|
5
|
+
|
|
6
|
+
from sciveo.common.tools.logger import *
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CryptoJsonData:
|
|
10
|
+
def __init__(self, base64_key=None) -> None:
|
|
11
|
+
if base64_key is None:
|
|
12
|
+
self.gen_key()
|
|
13
|
+
else:
|
|
14
|
+
self.key = base64.b64decode(base64_key)
|
|
15
|
+
|
|
16
|
+
def get_key(self):
|
|
17
|
+
return base64.b64encode(self.key).decode("utf-8")
|
|
18
|
+
|
|
19
|
+
def gen_key(self):
|
|
20
|
+
self.key = get_random_bytes(32)
|
|
21
|
+
return self.get_key()
|
|
22
|
+
|
|
23
|
+
def read_key(self, key_path):
|
|
24
|
+
with open(key_path, 'rb') as fp:
|
|
25
|
+
self.key = fp.read(32)
|
|
26
|
+
|
|
27
|
+
def write_key(self, key_path):
|
|
28
|
+
with open(key_path, 'wb') as fp:
|
|
29
|
+
fp.write(self.key)
|
|
30
|
+
|
|
31
|
+
def encrypt(self, plaintext, mode=AES.MODE_GCM):
|
|
32
|
+
iv = get_random_bytes(12)
|
|
33
|
+
cipher = AES.new(self.key, mode, nonce=iv)
|
|
34
|
+
data_encrypted, auth_tag = cipher.encrypt_and_digest(plaintext.encode())
|
|
35
|
+
return {
|
|
36
|
+
"encrypted": base64.b64encode(data_encrypted).decode("utf-8"),
|
|
37
|
+
"auth_tag": base64.b64encode(auth_tag).decode("utf-8"),
|
|
38
|
+
"iv": base64.b64encode(iv).decode("utf-8")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def decrypt(self, cipher_data, mode=AES.MODE_GCM):
|
|
42
|
+
cipher_text = base64.b64decode(cipher_data["encrypted"])
|
|
43
|
+
auth_tag = base64.b64decode(cipher_data["auth_tag"])
|
|
44
|
+
iv = base64.b64decode(cipher_data["iv"])
|
|
45
|
+
cipher = AES.new(self.key, mode, nonce=iv)
|
|
46
|
+
return cipher.decrypt_and_verify(cipher_text, auth_tag).decode("utf-8")
|
|
47
|
+
|
|
48
|
+
def encrypt_json(self, data):
|
|
49
|
+
data = json.dumps(data)
|
|
50
|
+
data = base64.b64encode(data.encode()).decode("utf-8")
|
|
51
|
+
return self.encrypt(data)
|
|
52
|
+
|
|
53
|
+
def decrypt_json(self, encrypted_data):
|
|
54
|
+
data = self.decrypt(encrypted_data)
|
|
55
|
+
data = base64.b64decode(data)
|
|
56
|
+
data = json.loads(data)
|
|
57
|
+
return data
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#
|
|
11
11
|
|
|
12
12
|
import threading
|
|
13
|
+
import signal
|
|
13
14
|
import time
|
|
14
15
|
|
|
15
16
|
from sciveo.common.tools.logger import *
|
|
@@ -17,6 +18,22 @@ from sciveo.common.tools.synchronized import ListQueue
|
|
|
17
18
|
from sciveo.api.upload import APIFileUploader
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
class SignalHandler:
|
|
22
|
+
def __init__(self, daemons):
|
|
23
|
+
self.daemons = daemons
|
|
24
|
+
|
|
25
|
+
signal.signal(signal.SIGINT, self.handler_int)
|
|
26
|
+
signal.signal(signal.SIGUSR1, self.handler_usr1)
|
|
27
|
+
|
|
28
|
+
def handler_int(self, signum, frame):
|
|
29
|
+
info(type(self).__name__, "INT signal received", signum, frame)
|
|
30
|
+
for daemon in self.daemons:
|
|
31
|
+
daemon.stop()
|
|
32
|
+
|
|
33
|
+
def handler_usr1(self, signum, frame):
|
|
34
|
+
info(type(self).__name__, "USR1 signal received", signum, frame)
|
|
35
|
+
|
|
36
|
+
|
|
20
37
|
class DaemonBase:
|
|
21
38
|
def __init__(self, num_threads=1, period=0):
|
|
22
39
|
self.is_running = False
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import string
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def random_password(length):
|
|
6
|
+
lower = string.ascii_lowercase
|
|
7
|
+
upper = string.ascii_uppercase
|
|
8
|
+
digits = string.digits
|
|
9
|
+
special = '!@#$%&'
|
|
10
|
+
|
|
11
|
+
# Ensure the password contains at least one character from each set
|
|
12
|
+
password = [
|
|
13
|
+
random.choice(lower),
|
|
14
|
+
random.choice(upper),
|
|
15
|
+
random.choice(digits),
|
|
16
|
+
random.choice(special)
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
all_chars = lower + upper + (2 * digits) + (3 * special)
|
|
20
|
+
password += random.choices(all_chars, k=length - 4)
|
|
21
|
+
random.shuffle(password)
|
|
22
|
+
return ''.join(password)
|
|
File without changes
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import cv2
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from sciveo.common.tools.logger import *
|
|
6
|
+
from sciveo.common.tools.timers import FPSCounter
|
|
7
|
+
from sciveo.network.tools import StreamSniffer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RTSPStreamSniffer(StreamSniffer):
|
|
11
|
+
def on_packet(self, packet):
|
|
12
|
+
if self.is_rtsp_packet(packet):
|
|
13
|
+
self.append_ip_packet(packet)
|
|
14
|
+
|
|
15
|
+
def is_rtsp_packet(self, packet):
|
|
16
|
+
return IP in packet and TCP in packet and (packet[TCP].dport == 554 or packet[TCP].sport == 554)
|
|
17
|
+
|
|
18
|
+
def get_rtsp_frames(self, ip_src):
|
|
19
|
+
frames = []
|
|
20
|
+
current_packets = self.get_ip_stream(ip_src)
|
|
21
|
+
for packet in current_packets:
|
|
22
|
+
frame = self.packet_to_frame(packet)
|
|
23
|
+
if frame is not None:
|
|
24
|
+
frames.append(frame)
|
|
25
|
+
return frames
|
|
26
|
+
|
|
27
|
+
def packet_to_frame(self, packet):
|
|
28
|
+
payload = bytes(packet[TCP].payload)
|
|
29
|
+
nparr = np.frombuffer(payload, np.uint8)
|
|
30
|
+
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
|
|
31
|
+
return frame
|
|
32
|
+
|
|
33
|
+
def play(self, ip_src):
|
|
34
|
+
fps = FPSCounter(tag=f"play {ip_src}")
|
|
35
|
+
while True:
|
|
36
|
+
frames = self.get_rtsp_frames(ip_src)
|
|
37
|
+
for frame in frames:
|
|
38
|
+
fps.update()
|
|
39
|
+
cv2.imshow(f'RTSP Stream from {ip_src}', frame)
|
|
40
|
+
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == '__main__':
|
|
45
|
+
sniffer = RTSPStreamSniffer(iface="eth0")
|
|
46
|
+
sniffer.start()
|
|
47
|
+
|
|
48
|
+
camera_ips = []
|
|
49
|
+
|
|
50
|
+
threads = []
|
|
51
|
+
for ip in camera_ips:
|
|
52
|
+
t = threading.Thread(target=sniffer.play, args=(ip,))
|
|
53
|
+
t.start()
|
|
54
|
+
threads.append(t)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
while True:
|
|
58
|
+
pass
|
|
59
|
+
except KeyboardInterrupt:
|
|
60
|
+
sniffer.stop_sniffing()
|
|
61
|
+
for t in threads:
|
|
62
|
+
t.join()
|
|
63
|
+
cv2.destroyAllWindows()
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import socket
|
|
13
13
|
import threading
|
|
14
|
+
from scapy.all import sniff, IP, TCP
|
|
14
15
|
|
|
15
16
|
from sciveo.common.tools.logger import *
|
|
16
17
|
from sciveo.common.tools.timers import Timer
|
|
@@ -92,5 +93,60 @@ class NetworkTools:
|
|
|
92
93
|
pass
|
|
93
94
|
|
|
94
95
|
|
|
96
|
+
|
|
97
|
+
class StreamSniffer:
|
|
98
|
+
def __init__(self, iface=None):
|
|
99
|
+
self.iface = iface
|
|
100
|
+
self.running = False
|
|
101
|
+
self.lock = threading.Lock()
|
|
102
|
+
self.streams = {}
|
|
103
|
+
|
|
104
|
+
def start(self):
|
|
105
|
+
self.running = True
|
|
106
|
+
self.sniff_thread = threading.Thread(target=self.sniff_packets)
|
|
107
|
+
self.sniff_thread.start()
|
|
108
|
+
|
|
109
|
+
def stop(self):
|
|
110
|
+
debug(type(self).__name__, "stopping...")
|
|
111
|
+
self.running = False
|
|
112
|
+
self.sniff_thread.join()
|
|
113
|
+
|
|
114
|
+
def sniff_packets(self):
|
|
115
|
+
debug(type(self).__name__, "start sniffing on", self.iface)
|
|
116
|
+
sniff(iface=self.iface, prn=self.on_packet, stop_filter=self.should_stop)
|
|
117
|
+
|
|
118
|
+
def on_packet(self, packet):
|
|
119
|
+
if IP in packet:
|
|
120
|
+
self.append_ip_packet(packet)
|
|
121
|
+
|
|
122
|
+
def should_stop(self, packet):
|
|
123
|
+
return not self.running
|
|
124
|
+
|
|
125
|
+
def append_ip_packet(self, packet):
|
|
126
|
+
ip_src = packet[IP].src
|
|
127
|
+
with self.lock:
|
|
128
|
+
self.streams.setdefault(ip_src, [])
|
|
129
|
+
self.streams[ip_src].append(packet)
|
|
130
|
+
|
|
131
|
+
def get_ip_stream(self, ip):
|
|
132
|
+
current_packets = []
|
|
133
|
+
with self.lock:
|
|
134
|
+
if ip in self.streams:
|
|
135
|
+
current_packets = self.streams[ip][:]
|
|
136
|
+
self.streams[ip] = []
|
|
137
|
+
return current_packets
|
|
138
|
+
|
|
139
|
+
def keys(self):
|
|
140
|
+
with self.lock:
|
|
141
|
+
return list(self.streams.keys())
|
|
142
|
+
|
|
143
|
+
|
|
95
144
|
if __name__ == "__main__":
|
|
96
|
-
debug(NetworkTools(timeout=1.0, localhost=False).scan_port(port=9901))
|
|
145
|
+
# debug(NetworkTools(timeout=1.0, localhost=False).scan_port(port=9901))
|
|
146
|
+
|
|
147
|
+
import time
|
|
148
|
+
sniffer = StreamSniffer(iface="en0")
|
|
149
|
+
sniffer.start()
|
|
150
|
+
time.sleep(5)
|
|
151
|
+
sniffer.stop()
|
|
152
|
+
debug(sniffer.keys())
|
|
@@ -18,11 +18,14 @@ sciveo/common/model.py
|
|
|
18
18
|
sciveo/common/optimizers.py
|
|
19
19
|
sciveo/common/sampling.py
|
|
20
20
|
sciveo/common/tools/__init__.py
|
|
21
|
+
sciveo/common/tools/compress.py
|
|
21
22
|
sciveo/common/tools/configuration.py
|
|
23
|
+
sciveo/common/tools/crypto.py
|
|
22
24
|
sciveo/common/tools/daemon.py
|
|
23
25
|
sciveo/common/tools/formating.py
|
|
24
26
|
sciveo/common/tools/hardware.py
|
|
25
27
|
sciveo/common/tools/logger.py
|
|
28
|
+
sciveo/common/tools/random.py
|
|
26
29
|
sciveo/common/tools/synchronized.py
|
|
27
30
|
sciveo/common/tools/timers.py
|
|
28
31
|
sciveo/content/__init__.py
|
|
@@ -32,9 +35,13 @@ sciveo/content/project.py
|
|
|
32
35
|
sciveo/content/runner.py
|
|
33
36
|
sciveo/monitoring/__init__.py
|
|
34
37
|
sciveo/monitoring/monitor.py
|
|
35
|
-
sciveo/monitoring/network.py
|
|
36
38
|
sciveo/monitoring/start.py
|
|
39
|
+
sciveo/network/__init__.py
|
|
40
|
+
sciveo/network/camera.py
|
|
41
|
+
sciveo/network/tools.py
|
|
42
|
+
test/test_compress.py
|
|
37
43
|
test/test_configuration.py
|
|
44
|
+
test/test_crypto.py
|
|
38
45
|
test/test_monitoring.py
|
|
39
46
|
test/test_runner.py
|
|
40
47
|
test/test_sampling.py
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from sciveo.common.tools.compress import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestEncoders(unittest.TestCase):
|
|
8
|
+
def test_compress_json(self):
|
|
9
|
+
zip = CompressJsonData()
|
|
10
|
+
j1 = {"AAA": [1, 2, 3], "BBB": {"CCC": 1, "DDD": 2, "EEE": 3}, "CC": 3}
|
|
11
|
+
j2 = zip.decompress(zip.compress(j1))
|
|
12
|
+
self.assertEqual(json.dumps(j1, sort_keys=True), json.dumps(j2, sort_keys=True))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == '__main__':
|
|
16
|
+
unittest.main()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from sciveo.common.tools.crypto import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestCrypto(unittest.TestCase):
|
|
7
|
+
def test_string(self):
|
|
8
|
+
c = CryptoJsonData()
|
|
9
|
+
m1 = "test message string encrypt and decrypt"
|
|
10
|
+
m2 = c.decrypt(c.encrypt(m1))
|
|
11
|
+
self.assertEqual(m1, m2)
|
|
12
|
+
|
|
13
|
+
def test_json(self):
|
|
14
|
+
c = CryptoJsonData()
|
|
15
|
+
j1 = {"A": 1, "B": []}
|
|
16
|
+
j2 = c.decrypt_json(c.encrypt_json(j1))
|
|
17
|
+
self.assertEqual(json.dumps(j1, sort_keys=True), json.dumps(j2, sort_keys=True))
|
|
18
|
+
|
|
19
|
+
def test_big_json(self):
|
|
20
|
+
c = CryptoJsonData()
|
|
21
|
+
j1 = {"test": 1, "L": [1,2,3,4], "W": "A", "B": "C", "D1": {1: 2, 2: 3, 3: 4}, "L2": [[1,2,3], [3,4,5]]}
|
|
22
|
+
j2 = c.decrypt_json(c.encrypt_json(j1))
|
|
23
|
+
self.assertEqual(json.dumps(j1, sort_keys=True), json.dumps(j2, sort_keys=True))
|
|
24
|
+
|
|
25
|
+
def test_key(self):
|
|
26
|
+
key = "OZ1IIdAh3b6h+E7fgIGo33rRsNT8Vg428GVC4FAGZGM="
|
|
27
|
+
c = CryptoJsonData(key)
|
|
28
|
+
m1 = "test message string encrypt and decrypt"
|
|
29
|
+
m2 = c.decrypt(c.encrypt(m1))
|
|
30
|
+
self.assertEqual(m1, m2)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == '__main__':
|
|
34
|
+
unittest.main()
|
sciveo-0.1.15/sciveo/version.py
DELETED
|
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
|