oscura 0.11.0__py3-none-any.whl → 0.12.0__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.
Files changed (32) hide show
  1. oscura/__init__.py +1 -1
  2. oscura/analyzers/binary/__init__.py +36 -0
  3. oscura/analyzers/binary/core/__init__.py +29 -0
  4. oscura/analyzers/binary/core/file_access.py +193 -0
  5. oscura/analyzers/binary/core/pipeline.py +161 -0
  6. oscura/analyzers/binary/core/results.py +217 -0
  7. oscura/analyzers/binary/detection/__init__.py +10 -0
  8. oscura/analyzers/binary/detection/encoding.py +624 -0
  9. oscura/analyzers/binary/detection/patterns.py +320 -0
  10. oscura/analyzers/binary/detection/structure.py +630 -0
  11. oscura/analyzers/binary/export/__init__.py +9 -0
  12. oscura/analyzers/binary/export/dissector.py +174 -0
  13. oscura/analyzers/binary/inference/__init__.py +15 -0
  14. oscura/analyzers/binary/inference/checksums.py +214 -0
  15. oscura/analyzers/binary/inference/fields.py +150 -0
  16. oscura/analyzers/binary/inference/sequences.py +232 -0
  17. oscura/analyzers/binary/inference/timestamps.py +210 -0
  18. oscura/analyzers/binary/visualization/__init__.py +9 -0
  19. oscura/analyzers/binary/visualization/structure_view.py +182 -0
  20. oscura/automotive/__init__.py +1 -1
  21. oscura/automotive/dtc/data.json +102 -17
  22. oscura/core/schemas/device_mapping.json +8 -2
  23. oscura/core/schemas/packet_format.json +24 -4
  24. oscura/core/schemas/protocol_definition.json +12 -2
  25. oscura/loaders/__init__.py +4 -1
  26. oscura/loaders/binary.py +284 -1
  27. oscura/sessions/legacy.py +80 -19
  28. {oscura-0.11.0.dist-info → oscura-0.12.0.dist-info}/METADATA +3 -3
  29. {oscura-0.11.0.dist-info → oscura-0.12.0.dist-info}/RECORD +32 -14
  30. {oscura-0.11.0.dist-info → oscura-0.12.0.dist-info}/WHEEL +0 -0
  31. {oscura-0.11.0.dist-info → oscura-0.12.0.dist-info}/entry_points.txt +0 -0
  32. {oscura-0.11.0.dist-info → oscura-0.12.0.dist-info}/licenses/LICENSE +0 -0
oscura/sessions/legacy.py CHANGED
@@ -18,6 +18,7 @@ import hashlib
18
18
  import hmac
19
19
  import pickle
20
20
  import secrets
21
+ import threading
21
22
  from dataclasses import dataclass, field
22
23
  from datetime import datetime
23
24
  from enum import Enum
@@ -26,6 +27,17 @@ from typing import Any
26
27
 
27
28
  from oscura.core.exceptions import SecurityError
28
29
 
30
+ # Global lock for security key generation to prevent race conditions (thread-level)
31
+ _KEY_GENERATION_LOCK = threading.Lock()
32
+
33
+ # Try to import fcntl for process-level file locking (Unix only)
34
+ try:
35
+ import fcntl
36
+
37
+ HAS_FCNTL = True
38
+ except ImportError:
39
+ HAS_FCNTL = False
40
+
29
41
  # Session file format constants
30
42
  _SESSION_MAGIC = b"OSC1" # Magic bytes for new format with signature
31
43
  _SESSION_SIGNATURE_SIZE = 32 # SHA256 hash size in bytes
@@ -38,33 +50,82 @@ def _get_security_key() -> bytes:
38
50
  with restrictive permissions (0o600). This provides better security than a
39
51
  shared hardcoded key.
40
52
 
53
+ Uses both thread-level and process-level locking to prevent race conditions
54
+ during parallel key generation.
55
+
41
56
  Returns:
42
57
  32-byte security key for HMAC signing.
43
58
  """
44
59
  key_file = Path.home() / ".oscura" / "session_key"
45
-
46
- if key_file.exists():
47
- # Load existing key
60
+ lock_file = Path.home() / ".oscura" / "session_key.lock"
61
+
62
+ # Thread-level lock first
63
+ with _KEY_GENERATION_LOCK:
64
+ # Check if key exists
65
+ if key_file.exists():
66
+ try:
67
+ return key_file.read_bytes()
68
+ except (OSError, PermissionError):
69
+ # Fall back to generating new key if can't read
70
+ pass
71
+
72
+ # Create parent directory
73
+ key_file.parent.mkdir(parents=True, exist_ok=True)
74
+
75
+ # Process-level file lock for parallel pytest workers
76
+ if HAS_FCNTL:
77
+ # Use file locking on Unix systems
78
+ lock_file.parent.mkdir(parents=True, exist_ok=True)
79
+ with open(lock_file, "w") as lock_fd:
80
+ try:
81
+ fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
82
+
83
+ # Double-check after acquiring file lock
84
+ if key_file.exists():
85
+ try:
86
+ key = key_file.read_bytes()
87
+ fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
88
+ return key
89
+ except (OSError, PermissionError):
90
+ pass
91
+
92
+ # Generate new random key
93
+ key = secrets.token_bytes(32)
94
+
95
+ # Write with restrictive permissions
96
+ try:
97
+ key_file.write_bytes(key)
98
+ key_file.chmod(0o600) # Owner read/write only
99
+ except (OSError, PermissionError):
100
+ # Can't write key file - continue with ephemeral key
101
+ pass
102
+
103
+ fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
104
+ return key
105
+ except OSError:
106
+ # File locking failed, continue without lock
107
+ pass
108
+
109
+ # Fallback without file locking (Windows or locking unavailable)
110
+ # Double-check one more time
111
+ if key_file.exists():
112
+ try:
113
+ return key_file.read_bytes()
114
+ except (OSError, PermissionError):
115
+ pass
116
+
117
+ # Generate new random key
118
+ key = secrets.token_bytes(32)
119
+
120
+ # Write with restrictive permissions
48
121
  try:
49
- return key_file.read_bytes()
122
+ key_file.write_bytes(key)
123
+ key_file.chmod(0o600) # Owner read/write only
50
124
  except (OSError, PermissionError):
51
- # Fall back to generating new key if can't read
125
+ # Can't write key file - continue with ephemeral key
52
126
  pass
53
127
 
54
- # Generate new random key
55
- key_file.parent.mkdir(parents=True, exist_ok=True)
56
- key = secrets.token_bytes(32)
57
-
58
- # Write with restrictive permissions
59
- try:
60
- key_file.write_bytes(key)
61
- key_file.chmod(0o600) # Owner read/write only
62
- except (OSError, PermissionError):
63
- # Can't write key file - continue with ephemeral key
64
- # This happens in read-only filesystems or restricted environments
65
- pass
66
-
67
- return key
128
+ return key
68
129
 
69
130
 
70
131
  _SECURITY_KEY = _get_security_key()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oscura
3
- Version: 0.11.0
3
+ Version: 0.12.0
4
4
  Summary: Python framework for hardware reverse engineering: signal analysis, protocol decoding, and automated dissector generation. Unified workflows from oscilloscope captures to Wireshark dissectors with IEEE-compliant measurements.
5
5
  Project-URL: Homepage, https://github.com/oscura-re/oscura
6
6
  Project-URL: Documentation, https://github.com/oscura-re/oscura/tree/main/docs
@@ -421,7 +421,7 @@ python3 .claude/hooks/validate_all.py # Must pass 5/5
421
421
 
422
422
  ## Project Status
423
423
 
424
- **Version**: [0.10.0](https://github.com/oscura-re/oscura/releases/latest) (2026-02-03)
424
+ **Version**: [0.12.0](https://github.com/oscura-re/oscura/releases/latest) (2026-02-03)
425
425
 
426
426
  **Active Development**: Hypothesis-driven RE workflows, automotive protocol analysis (CAN-FD, J1939, OBD-II, UDS), unknown protocol inference (state machines, field detection, CRC recovery), multi-format loading, export automation
427
427
 
@@ -449,7 +449,7 @@ python3 .claude/hooks/validate_all.py # Must pass 5/5
449
449
  author = {Oscura Contributors},
450
450
  year = {2026},
451
451
  url = {https://github.com/oscura-re/oscura},
452
- version = {0.10.0}
452
+ version = {0.12.0}
453
453
  }
454
454
  ```
455
455
 
@@ -1,4 +1,4 @@
1
- oscura/__init__.py,sha256=DwhB48tFYd9xipcGCvkakl1Kskrj817d2wOnTYtIqXI,19119
1
+ oscura/__init__.py,sha256=H-vPSx9MzJhUffDN4AjAFiJ1xsrUCiaKp_z0o-PdgIY,19119
2
2
  oscura/__main__.py,sha256=6qveGY8VHAHbxcrvxg8V4qxDCH0w0p1AMejDVHzVc88,11998
3
3
  oscura/convenience.py,sha256=YQgUr8zf386pQaOjXfNYhVL2NVUydRDVLoJizQW5_SU,29293
4
4
  oscura/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -8,6 +8,24 @@ oscura/analyzers/entropy.py,sha256=R3grNUbsPAyE5G3CwlvTgzWj_BLYFiJIXMLXrzMbDb8,2
8
8
  oscura/analyzers/measurements.py,sha256=ng5Qt2jyAvfKw3JQbJY_JNUqAOJEZwPo3UWa0xSg5Xk,697
9
9
  oscura/analyzers/signal_classification.py,sha256=-QSErG3WwLvv8mmM9WmcSszm9vbf8xHxrGwMmPlQUDk,17645
10
10
  oscura/analyzers/validation.py,sha256=uhpnGi9KP-yvKnpTr7U_XyvalKyMGvocpWhvO-Rltj8,23694
11
+ oscura/analyzers/binary/__init__.py,sha256=ZvtDnPVEnJsUwpCPOsqquYbwrTAftQ8fuANZHAUELok,805
12
+ oscura/analyzers/binary/core/__init__.py,sha256=fMn_vyTMRxOkbMDN5bHsoBL-mLMpCeTZFsFDguUWtYs,601
13
+ oscura/analyzers/binary/core/file_access.py,sha256=3Vj-Vo41biQ-Er5ggHiHnJw7J8MWSRHWL3TW9y6UVfs,6083
14
+ oscura/analyzers/binary/core/pipeline.py,sha256=8hqHfZec4g9GxDlUl86x-1wa2GA9DpXEldDFszMV1jg,5637
15
+ oscura/analyzers/binary/core/results.py,sha256=Z0f2X8LlCLu8waQCG91vMY0knCKGSs03DWIjz68rkIU,5991
16
+ oscura/analyzers/binary/detection/__init__.py,sha256=CJwb5hMpd6EmVtPfXX9NquBAW8RdYPi_vbuOqTpEZv0,388
17
+ oscura/analyzers/binary/detection/encoding.py,sha256=0xp8BiTb8EDmrFOGyOGkSs9I0-t7wpse11RWdEnJF98,22398
18
+ oscura/analyzers/binary/detection/patterns.py,sha256=BDgLU75sP_FbuFK72vK6z7v7Fkyo-L6naviZeEMwJ2E,11418
19
+ oscura/analyzers/binary/detection/structure.py,sha256=NcPXEREXEF5jVU1on-AQrnn8JwN5EsJatj_7LY36lQM,22879
20
+ oscura/analyzers/binary/export/__init__.py,sha256=UxTqVlZp6jdlIXDD2HaS8vJZYagMDrxJ_wcM7TAyYhA,190
21
+ oscura/analyzers/binary/export/dissector.py,sha256=oG1idIdmmZk4AJy4V9nqA9Qj6zAwVz-OQKTJk9Np7Ew,5378
22
+ oscura/analyzers/binary/inference/__init__.py,sha256=I3esl6ZGklO16D1HkzlQnIlZ_6pUAxCCHYeggk8YWEc,483
23
+ oscura/analyzers/binary/inference/checksums.py,sha256=8xWGhYaWo7thqFq1BWGMOIRF0r0aXYaRHWwC6OyFoT0,6051
24
+ oscura/analyzers/binary/inference/fields.py,sha256=SeI9OcmnWIB5KXA2J1DJceUbnX0FFoKyMkZX-tp0aJA,4915
25
+ oscura/analyzers/binary/inference/sequences.py,sha256=3pHuT9Mihd_YakncPN7kMIsc0ZGrrtfFDEh4CFOTjXs,6818
26
+ oscura/analyzers/binary/inference/timestamps.py,sha256=FFpbzyATaYrKorJACxhFkEkw4s0Tfz-LOZsUu256iGA,6537
27
+ oscura/analyzers/binary/visualization/__init__.py,sha256=M8XHuO73DgEheE6bMv0DM_61CxRXHeLOm_mjJ2jpBNA,211
28
+ oscura/analyzers/binary/visualization/structure_view.py,sha256=HrAeMIeNn-0rQEdUjDmgl2Fr4o1puZYAtpxrvKOS7S8,5188
11
29
  oscura/analyzers/digital/__init__.py,sha256=CrZxLveYI-nZ7INCZg-4zp8UP_uQRpMmX2vljzudJ6s,4228
12
30
  oscura/analyzers/digital/bus.py,sha256=Wf3QUKNSxzXaWItR1rdf32kELayywrIg0TC-OhKEub0,22717
13
31
  oscura/analyzers/digital/clock.py,sha256=2WihQyf2fUlKTDAOKrhQSStiuUw711CvR6bMbkiliAc,26088
@@ -163,7 +181,7 @@ oscura/api/server/templates/reports.html,sha256=LPdGkX-gXlg10FqNckB4WnY5eix0Tibh
163
181
  oscura/api/server/templates/session_detail.html,sha256=_NpjSi63fPulhWAJc2qhvN6cll3J3_TQ1mOp_ejf7Ns,2850
164
182
  oscura/api/server/templates/sessions.html,sha256=aAARmctGTaU7f-mtCpy-p13GRdTvR4jqTZ5MPIgbhG4,2346
165
183
  oscura/api/server/templates/waveforms.html,sha256=vxG9sPxcspsyV0ylpXf_8FzpTYDazPQcempY9iGljQ0,1977
166
- oscura/automotive/__init__.py,sha256=VCrOyBrV1S6fhgyEZY7GqZRbv6Yf8J2h_FV5gPEHdsI,2768
184
+ oscura/automotive/__init__.py,sha256=gNfPcgjhMxQKzIA0SS2EkRghnVT2uJU8OAM7C3WkEBo,2768
167
185
  oscura/automotive/visualization.py,sha256=LD6Gia3kDqoB_jQkOeVmyRVLv1BPuTUVj6lJMVtbQWg,10664
168
186
  oscura/automotive/can/__init__.py,sha256=ZYxC8tMMi9Drm9adkH5yklypBTfIbf3D7BYA2SUp9fE,1491
169
187
  oscura/automotive/can/analysis.py,sha256=0z6MycxuJGusqDQhYEpHnGRmDw3OMf5yDbS8zI6GJO0,11251
@@ -181,7 +199,7 @@ oscura/automotive/dbc/__init__.py,sha256=HZlM2WAaaglpX4C9tJVkF7uZiaHW4iUPQAbhfJY
181
199
  oscura/automotive/dbc/generator.py,sha256=ayhwTwMjZlzh70fihVSTRFmDWEuGDZgwUYArWFG6TcM,29823
182
200
  oscura/automotive/dbc/parser.py,sha256=C5SL1bfJFZp0CYsw-ff8ysJ_57Us9dBoHZ1t6LVLGbo,4421
183
201
  oscura/automotive/dtc/__init__.py,sha256=09CgvnClJTQIvzgDOQ22CbcjGAg_zOhPlbm1-k-gl30,895
184
- oscura/automotive/dtc/data.json,sha256=5pddTolfBJjwimwp5epiMjUqSngZ1dur9LQlcHfdjrA,79331
202
+ oscura/automotive/dtc/data.json,sha256=OrymnbjQkVMdJlIeQ6MUDIihkd9Kea-YvAizZwOZWcc,80011
185
203
  oscura/automotive/dtc/database.py,sha256=Ee1Jd4CbP5T4LON0Y2PdOkgdISHa8jf8c6znb0S_L00,9582
186
204
  oscura/automotive/flexray/__init__.py,sha256=2RuW8TR4M3tSDEfcj-pJQpGGSxGaw5GdyGSvjMnU8Lk,938
187
205
  oscura/automotive/flexray/analyzer.py,sha256=UG3e9tJSHGV7aR3WKwfVCrNDSVlT7ZgFm7vgCcw0qOo,16727
@@ -290,9 +308,9 @@ oscura/core/plugins/registry.py,sha256=XNtq0rBuppC1Z5V5RH74afW-LBnWSLc33lCE6BDZK
290
308
  oscura/core/plugins/versioning.py,sha256=d18sXMbgeWy_dVNaM7JWvCVIF6VgpnjIbjP8gdFfgSs,10785
291
309
  oscura/core/schemas/__init__.py,sha256=W33kQp0A8v9qZevqjm3T-1Fjrnou5cz0WCAbLRkwbgY,4327
292
310
  oscura/core/schemas/bus_configuration.json,sha256=gpcDsg04760KCaLeIDuWvP6RzRUcPZuQplJbe7xpc8E,9562
293
- oscura/core/schemas/device_mapping.json,sha256=I87-MWnXldVWIXRC1H-WgzNLszymRdnaxwE3B1z8qys,5415
294
- oscura/core/schemas/packet_format.json,sha256=NVa4RtwSye9QgD1pBi67nuCDRsVljudCpBBGjmZsMqk,12567
295
- oscura/core/schemas/protocol_definition.json,sha256=lThVXTWzh7GxN-XNb3h8Bh20l1NZUigivWBb04xvogs,11116
311
+ oscura/core/schemas/device_mapping.json,sha256=sYOcc2zSe0rmMQN_vtg3Y5XeeDMktAO1ar8vAWl-E1M,5499
312
+ oscura/core/schemas/packet_format.json,sha256=y2KavMGeOUlmjDq7AW_85bfTk3nHlGPuistpuVDdlAk,12893
313
+ oscura/core/schemas/protocol_definition.json,sha256=VPHkgY4fAI-hUiRBtiqZvDNUGjp6_7O4xdi1z36IhCI,11256
296
314
  oscura/correlation/__init__.py,sha256=4H5lCJqBBG3_10oIPsdIOyCij8FlKtMxLp3SAYvSsRg,1537
297
315
  oscura/correlation/multi_protocol.py,sha256=Lce9AF2iqenpGRMYpSJ_LbXBA7nVK5mLbDEwHhbVldg,28260
298
316
  oscura/discovery/__init__.py,sha256=ytYa_s4PfKxRRopOdUGsmzUIDPevH25ze_VytBEX2Cw,1232
@@ -386,8 +404,8 @@ oscura/jupyter/exploratory/unknown.py,sha256=KaxpoP9tW9E7Ld16_3VaXaKszfcU2uw62Id
386
404
  oscura/jupyter/ui/__init__.py,sha256=XQJh89b_xRe1CB8jssjIdbVgQeLCplFzSkCiXQYKXFU,935
387
405
  oscura/jupyter/ui/formatters.py,sha256=roXZhaNLgypb30T6EGF805cDkrqsAh_RQ978iGLtlAU,13580
388
406
  oscura/jupyter/ui/progressive_display.py,sha256=Ew-xXek_f6-XkR0CZymyzYbYkbXn8qCZS6Usk2n86dQ,11993
389
- oscura/loaders/__init__.py,sha256=aqPopCVPBeZkreR38zvo-Lh94gk815t7o4NilUMRfic,20235
390
- oscura/loaders/binary.py,sha256=WYyoIHAkjfrJcCN0Rd3zjcAAUK5HZ1fu41FhgKhtkz0,5057
407
+ oscura/loaders/__init__.py,sha256=qwIA1SULrb1M6rRq09PoiXu4T-jyTT2NzZFrs6kC0Fw,20394
408
+ oscura/loaders/binary.py,sha256=zQn5JtNZ7F1-C0Ti1VhOhZ2Yh64QlFmZFuCrg2gaJ6Y,14597
391
409
  oscura/loaders/chipwhisperer.py,sha256=RK1dDdyRAr__4qA68CSdxxbXqk0btGgHRj6A6fHF3uc,12655
392
410
  oscura/loaders/configurable.py,sha256=7ms5dlVzF7PAam8fJRzBDRdLznfiKdonuYE7piPxbAQ,44478
393
411
  oscura/loaders/csv.py,sha256=hjToCQkXQEMUCOSBTf3a1d4AAsntvxYbW_jiccQ9JaM,918
@@ -470,7 +488,7 @@ oscura/sessions/__init__.py,sha256=gJMEZezGxt0KniCQNFinp65B9HwDDfmXkYiq3n4wWYk,2
470
488
  oscura/sessions/base.py,sha256=JjMO-QybHS55OqFZ4jZC1DTVehTKrxOgMPlSA5bwlkk,10847
471
489
  oscura/sessions/blackbox.py,sha256=nk1ZKapxwDSIHmweD9x7kSbiMOOLVdMqVN-lavRhYYI,26039
472
490
  oscura/sessions/generic.py,sha256=roecnb2ftlzyOyKioaB4N0klUJKfRsbPN1WyWO-YEws,6660
473
- oscura/sessions/legacy.py,sha256=RYerJGiO-Wov62phQhhtMHXJcV9bGeWxHI_PQGXKT6E,25631
491
+ oscura/sessions/legacy.py,sha256=sXwGQ2mUQ0iGhiu8jWa9wmbYyKgCvqiehgD7PgbyoT4,27871
474
492
  oscura/side_channel/__init__.py,sha256=3-vgWWiaabnfZL6tXvzRtvXoUw4Gmquue0oFZ10amrU,1141
475
493
  oscura/utils/__init__.py,sha256=VGd2Hzqy1j47UtheI73Hc8GOPwIAi2SWX34CbOxhk1A,2771
476
494
  oscura/utils/autodetect.py,sha256=cP-_be6XK9neO28J2le1iZ8YLvPmfpc8L-p6KAlA6h8,9324
@@ -570,8 +588,8 @@ oscura/workflows/batch/logging.py,sha256=6YkTrOA2OSiRjYHmtRn-lL2wyNpya0sggVkgxsz
570
588
  oscura/workflows/batch/metrics.py,sha256=InbxaZmFQrANpp_RCcx5F3va55UaiQjhFJ-_SEKAS20,17322
571
589
  oscura/workflows/legacy/__init__.py,sha256=PqHw8AIWfP4-1lJEjCDC4c_O8GXYOcWodK9ciOnGJaU,409
572
590
  oscura/workflows/legacy/dag.py,sha256=tEhiWmOSdcEYKmrwYUETC0P5yN-_Cy9fEysPwTDVZ3A,12337
573
- oscura-0.11.0.dist-info/METADATA,sha256=YWJqgPrd73hr127e_dy1ip7sYIR0A7nF7Ab6PRcojqE,20170
574
- oscura-0.11.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
575
- oscura-0.11.0.dist-info/entry_points.txt,sha256=QLBxd-iTjBQ5HidaVSkLBwvUsqxSG1ZTJ6i-0juu960,48
576
- oscura-0.11.0.dist-info/licenses/LICENSE,sha256=p1_oEK-oqWDXMFSv5mKbyYkgW-CPbCnFUvdICu490aY,1077
577
- oscura-0.11.0.dist-info/RECORD,,
591
+ oscura-0.12.0.dist-info/METADATA,sha256=GJsEvV024r65hu9rlar5hc9sfk7saHdk8HuTqS8O5r8,20170
592
+ oscura-0.12.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
593
+ oscura-0.12.0.dist-info/entry_points.txt,sha256=QLBxd-iTjBQ5HidaVSkLBwvUsqxSG1ZTJ6i-0juu960,48
594
+ oscura-0.12.0.dist-info/licenses/LICENSE,sha256=p1_oEK-oqWDXMFSv5mKbyYkgW-CPbCnFUvdICu490aY,1077
595
+ oscura-0.12.0.dist-info/RECORD,,