chemql-python 1.2.1__tar.gz → 1.2.2__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.
- {chemql_python-1.2.1/src/chemql_python.egg-info → chemql_python-1.2.2}/PKG-INFO +6 -6
- {chemql_python-1.2.1 → chemql_python-1.2.2}/README.md +5 -5
- {chemql_python-1.2.1 → chemql_python-1.2.2}/pyproject.toml +1 -1
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/__init__.py +144 -37
- {chemql_python-1.2.1 → chemql_python-1.2.2/src/chemql_python.egg-info}/PKG-INFO +6 -6
- {chemql_python-1.2.1 → chemql_python-1.2.2}/LICENSE +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/setup.cfg +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/__main__.py +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/BondEnergies.json +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/MoleculeBonds.json +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/Molecules.json +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/PeriodicTableJSON.json +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/Reactions.json +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/THIRD_PARTY_LICENSES/PeriodicTableJSON.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/data/THIRD_PARTY_LICENSES/RHEA.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql/html/periodic_table.html +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql_python.egg-info/SOURCES.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql_python.egg-info/dependency_links.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql_python.egg-info/entry_points.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql_python.egg-info/requires.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/src/chemql_python.egg-info/top_level.txt +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/tests/test_external_molecule_lookup.py +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/tests/test_public_api.py +0 -0
- {chemql_python-1.2.1 → chemql_python-1.2.2}/tests/test_reactions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chemql-python
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: A chemistry-focused query language and REPL
|
|
5
5
|
Author-email: Mohammad Rakibul Islam <rakibulofficial1017@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -17,15 +17,15 @@ Dynamic: license-file
|
|
|
17
17
|
shell commands in one interactive environment.**
|
|
18
18
|
|
|
19
19
|
ChemQL is a command-line chemistry query language for exploring chemical
|
|
20
|
-
elements, molecules, and reactions. Version 1.2.
|
|
20
|
+
elements, molecules, and reactions. Version 1.2.2 combines database-style
|
|
21
21
|
chemistry queries, reaction tools, Python interoperability, reusable functions
|
|
22
22
|
and macros, and a persistent shell in one scriptable environment. It combines a small SQL-inspired
|
|
23
23
|
query syntax with a persistent Python environment, reaction utilities,
|
|
24
24
|
optional external molecule lookup, and tools for running repeatable
|
|
25
25
|
scripts.
|
|
26
26
|
|
|
27
|
-
> **Version covered by this README:** 1.2.
|
|
28
|
-
> The examples below describe the ChemQL 1.2.
|
|
27
|
+
> **Version covered by this README:** 1.2.2\
|
|
28
|
+
> The examples below describe the ChemQL 1.2.2 source. Dataset
|
|
29
29
|
> contents and external-service availability can affect individual
|
|
30
30
|
> lookup results.
|
|
31
31
|
|
|
@@ -538,7 +538,7 @@ queried or inspected from Python.
|
|
|
538
538
|
|
|
539
539
|
## Preprocessor, functions, and macros
|
|
540
540
|
|
|
541
|
-
ChemQL 1.2.
|
|
541
|
+
ChemQL 1.2.2 adds three ways to reuse values and logic. These declarations
|
|
542
542
|
are processed in source order: definitions affect later lines, not earlier
|
|
543
543
|
ones. They persist during the current ChemQL process/session; they are not
|
|
544
544
|
saved automatically between separate launches.
|
|
@@ -833,7 +833,7 @@ redirect a file into the command.
|
|
|
833
833
|
``` bash
|
|
834
834
|
chemql --version
|
|
835
835
|
chemql --upgrade
|
|
836
|
-
chemql --upgrade 1.2.
|
|
836
|
+
chemql --upgrade 1.2.2
|
|
837
837
|
```
|
|
838
838
|
|
|
839
839
|
`--upgrade` installs the latest published `chemql-python` release; supplying a
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
shell commands in one interactive environment.**
|
|
5
5
|
|
|
6
6
|
ChemQL is a command-line chemistry query language for exploring chemical
|
|
7
|
-
elements, molecules, and reactions. Version 1.2.
|
|
7
|
+
elements, molecules, and reactions. Version 1.2.2 combines database-style
|
|
8
8
|
chemistry queries, reaction tools, Python interoperability, reusable functions
|
|
9
9
|
and macros, and a persistent shell in one scriptable environment. It combines a small SQL-inspired
|
|
10
10
|
query syntax with a persistent Python environment, reaction utilities,
|
|
11
11
|
optional external molecule lookup, and tools for running repeatable
|
|
12
12
|
scripts.
|
|
13
13
|
|
|
14
|
-
> **Version covered by this README:** 1.2.
|
|
15
|
-
> The examples below describe the ChemQL 1.2.
|
|
14
|
+
> **Version covered by this README:** 1.2.2\
|
|
15
|
+
> The examples below describe the ChemQL 1.2.2 source. Dataset
|
|
16
16
|
> contents and external-service availability can affect individual
|
|
17
17
|
> lookup results.
|
|
18
18
|
|
|
@@ -525,7 +525,7 @@ queried or inspected from Python.
|
|
|
525
525
|
|
|
526
526
|
## Preprocessor, functions, and macros
|
|
527
527
|
|
|
528
|
-
ChemQL 1.2.
|
|
528
|
+
ChemQL 1.2.2 adds three ways to reuse values and logic. These declarations
|
|
529
529
|
are processed in source order: definitions affect later lines, not earlier
|
|
530
530
|
ones. They persist during the current ChemQL process/session; they are not
|
|
531
531
|
saved automatically between separate launches.
|
|
@@ -820,7 +820,7 @@ redirect a file into the command.
|
|
|
820
820
|
``` bash
|
|
821
821
|
chemql --version
|
|
822
822
|
chemql --upgrade
|
|
823
|
-
chemql --upgrade 1.2.
|
|
823
|
+
chemql --upgrade 1.2.2
|
|
824
824
|
```
|
|
825
825
|
|
|
826
826
|
`--upgrade` installs the latest published `chemql-python` release; supplying a
|
|
@@ -18,6 +18,8 @@ from prompt_toolkit.lexers import Lexer
|
|
|
18
18
|
import atexit
|
|
19
19
|
import uuid
|
|
20
20
|
import select
|
|
21
|
+
import queue
|
|
22
|
+
import threading
|
|
21
23
|
from prompt_toolkit.styles import Style
|
|
22
24
|
from prompt_toolkit.completion import Completer, Completion
|
|
23
25
|
import urllib.parse
|
|
@@ -45,7 +47,7 @@ __all__ = [
|
|
|
45
47
|
"__version__"
|
|
46
48
|
]
|
|
47
49
|
|
|
48
|
-
__version__ = "1.2.
|
|
50
|
+
__version__ = "1.2.2"
|
|
49
51
|
|
|
50
52
|
# Persistent preprocessor/function state for the current ChemQL session.
|
|
51
53
|
DEFINITIONS = {}
|
|
@@ -258,17 +260,15 @@ _shell_process = None
|
|
|
258
260
|
_shell_master_fd = None
|
|
259
261
|
_shell_prompt_ready = False
|
|
260
262
|
_shell_output_streamed = False
|
|
263
|
+
_shell_output_queue = None
|
|
264
|
+
_shell_reader_thread = None
|
|
261
265
|
_shell_prompt = f"__CHEMQL_PROMPT_{uuid.uuid4().hex}__"
|
|
262
266
|
|
|
263
267
|
|
|
264
268
|
def get_shell():
|
|
265
|
-
"""Return the persistent shell process.
|
|
266
|
-
|
|
267
|
-
On POSIX, use a pseudo-terminal so foreground commands such as `read`,
|
|
268
|
-
`read -p`, and interactive CLIs can receive keyboard input. Windows keeps
|
|
269
|
-
the pipe-based implementation until a ConPTY backend is added.
|
|
270
|
-
"""
|
|
269
|
+
"""Return the persistent OS shell process for the current platform."""
|
|
271
270
|
global _shell_process, _shell_master_fd, _shell_prompt_ready
|
|
271
|
+
global _shell_output_queue, _shell_reader_thread
|
|
272
272
|
|
|
273
273
|
if _shell_process is not None and _shell_process.poll() is None:
|
|
274
274
|
return _shell_process
|
|
@@ -277,14 +277,38 @@ def get_shell():
|
|
|
277
277
|
close_shell()
|
|
278
278
|
|
|
279
279
|
if os.name == "nt":
|
|
280
|
+
# Use PowerShell as ChemQL's native Windows shell. Its prompt function
|
|
281
|
+
# emits a private marker when a command finishes, so we do not append a
|
|
282
|
+
# marker to stdin (which would accidentally become Read-Host input).
|
|
283
|
+
setup = (
|
|
284
|
+
f"function global:prompt {{ [Console]::Out.WriteLine('{_shell_prompt}'); return '' }}"
|
|
285
|
+
)
|
|
280
286
|
_shell_process = subprocess.Popen(
|
|
281
|
-
["
|
|
287
|
+
["powershell.exe", "-NoLogo", "-NoProfile", "-NoExit", "-Command", setup],
|
|
282
288
|
stdin=subprocess.PIPE,
|
|
283
289
|
stdout=subprocess.PIPE,
|
|
284
290
|
stderr=subprocess.STDOUT,
|
|
285
291
|
text=True,
|
|
286
292
|
bufsize=1,
|
|
287
293
|
)
|
|
294
|
+
output_queue = queue.Queue()
|
|
295
|
+
_shell_output_queue = output_queue
|
|
296
|
+
process = _shell_process
|
|
297
|
+
|
|
298
|
+
def read_output():
|
|
299
|
+
try:
|
|
300
|
+
while True:
|
|
301
|
+
character = process.stdout.read(1) # type: ignore
|
|
302
|
+
if not character:
|
|
303
|
+
break
|
|
304
|
+
output_queue.put(character)
|
|
305
|
+
except (OSError, ValueError):
|
|
306
|
+
pass
|
|
307
|
+
finally:
|
|
308
|
+
output_queue.put(None)
|
|
309
|
+
|
|
310
|
+
_shell_reader_thread = threading.Thread(target=read_output, daemon=True)
|
|
311
|
+
_shell_reader_thread.start()
|
|
288
312
|
else:
|
|
289
313
|
import fcntl
|
|
290
314
|
import pty
|
|
@@ -434,47 +458,128 @@ def _run_shell_command_posix(command, marker=None):
|
|
|
434
458
|
return f"Shell error: {exc}"
|
|
435
459
|
|
|
436
460
|
|
|
437
|
-
def
|
|
461
|
+
def _run_shell_command_windows(command):
|
|
462
|
+
"""Run a command in persistent PowerShell and forward line input interactively."""
|
|
463
|
+
global _shell_prompt_ready, _shell_output_streamed
|
|
438
464
|
shell = get_shell()
|
|
439
|
-
|
|
440
|
-
|
|
465
|
+
output_queue = _shell_output_queue
|
|
466
|
+
if output_queue is None:
|
|
467
|
+
return "Shell error: PowerShell output reader was not initialized."
|
|
441
468
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
469
|
+
import msvcrt
|
|
470
|
+
|
|
471
|
+
def wait_for_prompt(stream_output):
|
|
472
|
+
collected = ""
|
|
473
|
+
streamed_pos = 0
|
|
474
|
+
marker = _shell_prompt
|
|
475
|
+
marker_len = len(marker)
|
|
476
|
+
stdin_is_tty = False
|
|
477
|
+
try:
|
|
478
|
+
stdin_is_tty = sys.stdin is not None and sys.stdin.isatty()
|
|
479
|
+
except (AttributeError, OSError, ValueError):
|
|
480
|
+
pass
|
|
481
|
+
pending_input = ""
|
|
445
482
|
|
|
446
|
-
# Windows pipe mode supports persistent commands, but not fully
|
|
447
|
-
# interactive programs yet; a ConPTY backend is needed for that.
|
|
448
|
-
shell.stdin.write(command + "\r\n" + f"echo {marker}\r\n") # type: ignore
|
|
449
|
-
shell.stdin.flush() # type: ignore
|
|
450
|
-
output = []
|
|
451
483
|
while True:
|
|
484
|
+
# While a shell command is running, pass complete lines typed by the
|
|
485
|
+
# user to PowerShell. This lets Read-Host receive real input rather
|
|
486
|
+
# than consuming a completion marker injected by ChemQL.
|
|
487
|
+
if stdin_is_tty:
|
|
488
|
+
try:
|
|
489
|
+
while msvcrt.kbhit(): #type:ignore
|
|
490
|
+
key = msvcrt.getwch() #type:ignore
|
|
491
|
+
if key in ("\x00", "\xe0"): #type:ignore
|
|
492
|
+
# Consume the second half of a Windows special key.
|
|
493
|
+
if msvcrt.kbhit(): #type:ignore
|
|
494
|
+
msvcrt.getwch() #type:ignore
|
|
495
|
+
elif key in ("\r", "\n"):
|
|
496
|
+
shell.stdin.write(pending_input + "\r\n") # type: ignore
|
|
497
|
+
shell.stdin.flush() # type: ignore
|
|
498
|
+
pending_input = ""
|
|
499
|
+
elif key == "\b":
|
|
500
|
+
pending_input = pending_input[:-1]
|
|
501
|
+
elif key == "\x03":
|
|
502
|
+
# Ctrl-C is sent as a line input; reset is safer than
|
|
503
|
+
# leaving ChemQL stuck in a nested interactive prompt.
|
|
504
|
+
close_shell()
|
|
505
|
+
return None
|
|
506
|
+
elif key >= " " and key != "\x7f":
|
|
507
|
+
pending_input += key
|
|
508
|
+
except (OSError, ValueError):
|
|
509
|
+
stdin_is_tty = False
|
|
510
|
+
|
|
452
511
|
try:
|
|
453
|
-
|
|
454
|
-
except
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
512
|
+
character = output_queue.get(timeout=0.04)
|
|
513
|
+
except queue.Empty:
|
|
514
|
+
continue
|
|
515
|
+
if character is None:
|
|
516
|
+
return None
|
|
517
|
+
|
|
518
|
+
collected += character
|
|
519
|
+
marker_pos = collected.find(marker)
|
|
520
|
+
if marker_pos >= 0:
|
|
521
|
+
visible = collected[:marker_pos]
|
|
522
|
+
if stream_output and marker_pos > streamed_pos:
|
|
523
|
+
sys.stdout.write(collected[streamed_pos:marker_pos])
|
|
524
|
+
sys.stdout.flush()
|
|
525
|
+
_shell_output_streamed = True
|
|
526
|
+
return visible.replace("\r\n", "\n").rstrip("\r\n ")
|
|
527
|
+
|
|
528
|
+
if stream_output:
|
|
529
|
+
# Stream immediately, retaining the full output for history and
|
|
530
|
+
# only withholding a suffix that could begin the prompt marker.
|
|
531
|
+
overlap = 0
|
|
532
|
+
max_overlap = min(marker_len - 1, len(collected))
|
|
533
|
+
for size in range(max_overlap, 0, -1):
|
|
534
|
+
if collected.endswith(marker[:size]):
|
|
535
|
+
overlap = size
|
|
536
|
+
break
|
|
537
|
+
safe_end = len(collected) - overlap
|
|
538
|
+
if safe_end > streamed_pos:
|
|
539
|
+
sys.stdout.write(collected[streamed_pos:safe_end])
|
|
540
|
+
sys.stdout.flush()
|
|
541
|
+
_shell_output_streamed = True
|
|
542
|
+
streamed_pos = safe_end
|
|
466
543
|
|
|
544
|
+
if not _shell_prompt_ready:
|
|
545
|
+
initial = wait_for_prompt(stream_output=False)
|
|
546
|
+
if initial is None:
|
|
547
|
+
close_shell()
|
|
548
|
+
return "Shell session terminated."
|
|
549
|
+
_shell_prompt_ready = True
|
|
550
|
+
|
|
551
|
+
try:
|
|
552
|
+
shell.stdin.write(command.replace("\n", "\r\n") + "\r\n") # type: ignore
|
|
553
|
+
shell.stdin.flush() # type: ignore
|
|
554
|
+
result = wait_for_prompt(stream_output=True)
|
|
555
|
+
if result is None:
|
|
556
|
+
close_shell()
|
|
557
|
+
return "Shell session terminated."
|
|
558
|
+
return result
|
|
559
|
+
except (BrokenPipeError, OSError, ValueError) as exc:
|
|
560
|
+
close_shell()
|
|
561
|
+
return f"Shell error: {exc}"
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def run_shell_command(command):
|
|
565
|
+
global _shell_output_streamed
|
|
566
|
+
command = command.replace("\r\n", "\n").replace("\r", "\n").rstrip("\n")
|
|
567
|
+
try:
|
|
568
|
+
if os.name == "nt":
|
|
569
|
+
if command.strip().casefold() in {"powershell", "powershell.exe", "pwsh", "pwsh.exe"}:
|
|
570
|
+
return "ChemQL already uses PowerShell on Windows; run the command directly instead of starting a nested shell."
|
|
571
|
+
_shell_output_streamed = False
|
|
572
|
+
return _run_shell_command_windows(command)
|
|
573
|
+
return _run_shell_command_posix(command)
|
|
467
574
|
except KeyboardInterrupt:
|
|
468
575
|
close_shell()
|
|
469
576
|
return "Shell command interrupted. Shell session was reset."
|
|
470
|
-
except (BrokenPipeError, OSError) as exc:
|
|
471
|
-
close_shell()
|
|
472
|
-
return f"Shell error: {exc}"
|
|
473
577
|
|
|
474
578
|
|
|
475
579
|
def close_shell():
|
|
476
580
|
"""Clean up the persistent shell and its pseudo-terminal on exit."""
|
|
477
581
|
global _shell_process, _shell_master_fd, _shell_prompt_ready
|
|
582
|
+
global _shell_output_queue, _shell_reader_thread
|
|
478
583
|
|
|
479
584
|
if _shell_process is not None:
|
|
480
585
|
if _shell_process.poll() is None:
|
|
@@ -496,6 +601,8 @@ def close_shell():
|
|
|
496
601
|
pass
|
|
497
602
|
_shell_master_fd = None
|
|
498
603
|
_shell_prompt_ready = False
|
|
604
|
+
_shell_output_queue = None
|
|
605
|
+
_shell_reader_thread = None
|
|
499
606
|
|
|
500
607
|
|
|
501
608
|
atexit.register(close_shell)
|
|
@@ -3229,7 +3336,7 @@ def execute(arguments, query_text=None, positions=None):
|
|
|
3229
3336
|
|
|
3230
3337
|
if arguments[0].lower() == "macros":
|
|
3231
3338
|
return "\n".join([f"@{name} = {value}" for name, value in MACROS.items()]) if MACROS else "No macros."
|
|
3232
|
-
|
|
3339
|
+
|
|
3233
3340
|
if arguments[0] == "conditions":
|
|
3234
3341
|
if len(arguments) != 1:
|
|
3235
3342
|
return "Usage: conditions"
|
|
@@ -3584,7 +3691,7 @@ class ChemqlLexer(Lexer):
|
|
|
3584
3691
|
"findmol", "findre", "set", "add", "remove", "react",
|
|
3585
3692
|
"balance", "conditions", "view", "help", "dump", "version",
|
|
3586
3693
|
"return", "union", "intersection", "let", "unset", "variables",
|
|
3587
|
-
"macros", "definitions", "arguments"
|
|
3694
|
+
"macros", "definitions", "arguments",
|
|
3588
3695
|
}
|
|
3589
3696
|
|
|
3590
3697
|
OPERATORS = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chemql-python
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: A chemistry-focused query language and REPL
|
|
5
5
|
Author-email: Mohammad Rakibul Islam <rakibulofficial1017@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -17,15 +17,15 @@ Dynamic: license-file
|
|
|
17
17
|
shell commands in one interactive environment.**
|
|
18
18
|
|
|
19
19
|
ChemQL is a command-line chemistry query language for exploring chemical
|
|
20
|
-
elements, molecules, and reactions. Version 1.2.
|
|
20
|
+
elements, molecules, and reactions. Version 1.2.2 combines database-style
|
|
21
21
|
chemistry queries, reaction tools, Python interoperability, reusable functions
|
|
22
22
|
and macros, and a persistent shell in one scriptable environment. It combines a small SQL-inspired
|
|
23
23
|
query syntax with a persistent Python environment, reaction utilities,
|
|
24
24
|
optional external molecule lookup, and tools for running repeatable
|
|
25
25
|
scripts.
|
|
26
26
|
|
|
27
|
-
> **Version covered by this README:** 1.2.
|
|
28
|
-
> The examples below describe the ChemQL 1.2.
|
|
27
|
+
> **Version covered by this README:** 1.2.2\
|
|
28
|
+
> The examples below describe the ChemQL 1.2.2 source. Dataset
|
|
29
29
|
> contents and external-service availability can affect individual
|
|
30
30
|
> lookup results.
|
|
31
31
|
|
|
@@ -538,7 +538,7 @@ queried or inspected from Python.
|
|
|
538
538
|
|
|
539
539
|
## Preprocessor, functions, and macros
|
|
540
540
|
|
|
541
|
-
ChemQL 1.2.
|
|
541
|
+
ChemQL 1.2.2 adds three ways to reuse values and logic. These declarations
|
|
542
542
|
are processed in source order: definitions affect later lines, not earlier
|
|
543
543
|
ones. They persist during the current ChemQL process/session; they are not
|
|
544
544
|
saved automatically between separate launches.
|
|
@@ -833,7 +833,7 @@ redirect a file into the command.
|
|
|
833
833
|
``` bash
|
|
834
834
|
chemql --version
|
|
835
835
|
chemql --upgrade
|
|
836
|
-
chemql --upgrade 1.2.
|
|
836
|
+
chemql --upgrade 1.2.2
|
|
837
837
|
```
|
|
838
838
|
|
|
839
839
|
`--upgrade` installs the latest published `chemql-python` release; supplying a
|
|
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
|