python-lab-toolkit 1.0.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 (86) hide show
  1. pylab/__init__.py +43 -0
  2. pylab/cli.py +282 -0
  3. pylab/data/Data.csv +11 -0
  4. pylab/data/alphabet_stock_data.csv +143 -0
  5. pylab/data/breast-cancer.csv +351 -0
  6. pylab/data/dirtydata.csv +33 -0
  7. pylab/data/groceries.csv +359 -0
  8. pylab/data/iris.csv +151 -0
  9. pylab/data/rainfall.csv +151 -0
  10. pylab/data/students.csv +7 -0
  11. pylab/data/winequality-red.csv +1601 -0
  12. pylab/data/winequality-white.csv +2401 -0
  13. pylab/datasets.py +277 -0
  14. pylab/environment.py +136 -0
  15. pylab/errors.py +53 -0
  16. pylab/generator.py +216 -0
  17. pylab/registry.py +562 -0
  18. pylab/templates/q1/variable_validator.py +43 -0
  19. pylab/templates/q10/password_strength.py +42 -0
  20. pylab/templates/q11/recursion_math.py +28 -0
  21. pylab/templates/q12/main_analyzer.py +46 -0
  22. pylab/templates/q12/text_analyzer.py +16 -0
  23. pylab/templates/q12/text_preprocessor.py +15 -0
  24. pylab/templates/q13/student.py +26 -0
  25. pylab/templates/q14/circle.py +26 -0
  26. pylab/templates/q15/employee_salary.py +46 -0
  27. pylab/templates/q16/smart_calculator.py +51 -0
  28. pylab/templates/q17/complex_number.py +43 -0
  29. pylab/templates/q18/vehicle_inheritance.py +43 -0
  30. pylab/templates/q19/file_word_counter.py +48 -0
  31. pylab/templates/q19/sample.txt +6 -0
  32. pylab/templates/q2/single_number.py +26 -0
  33. pylab/templates/q20/age_validator.py +27 -0
  34. pylab/templates/q21/transaction_manager.py +45 -0
  35. pylab/templates/q22/date_formatter.py +30 -0
  36. pylab/templates/q23/rainfall_analyzer.py +73 -0
  37. pylab/templates/q24/student_marks.py +58 -0
  38. pylab/templates/q25/library_manager.py +182 -0
  39. pylab/templates/q26/mysql_employee_manager.py +239 -0
  40. pylab/templates/q27/crud_client.py +98 -0
  41. pylab/templates/q27/mock_server.py +85 -0
  42. pylab/templates/q28/index.html +33 -0
  43. pylab/templates/q28/login_handler.py +31 -0
  44. pylab/templates/q28/server.py +44 -0
  45. pylab/templates/q29/index.html +50 -0
  46. pylab/templates/q29/register_handler.py +42 -0
  47. pylab/templates/q29/server.py +42 -0
  48. pylab/templates/q3/string_operations.py +32 -0
  49. pylab/templates/q30/crud_handler.py +60 -0
  50. pylab/templates/q30/database.py +66 -0
  51. pylab/templates/q30/index.html +59 -0
  52. pylab/templates/q30/server.py +51 -0
  53. pylab/templates/q31/numpy_matrix.py +40 -0
  54. pylab/templates/q32/numpy_slicing.py +43 -0
  55. pylab/templates/q33/pandas_students.py +41 -0
  56. pylab/templates/q34/pandas_salary.py +37 -0
  57. pylab/templates/q35/sales_barchart.py +58 -0
  58. pylab/templates/q36/weather_plot.py +50 -0
  59. pylab/templates/q37/age_categorization.py +38 -0
  60. pylab/templates/q38/concat_rows.py +38 -0
  61. pylab/templates/q39/concat_cols.py +38 -0
  62. pylab/templates/q4/menu_string_processor.py +68 -0
  63. pylab/templates/q40/concat_merge.py +44 -0
  64. pylab/templates/q41/pandas_joins.py +46 -0
  65. pylab/templates/q42/groupby_school.py +32 -0
  66. pylab/templates/q43/groupby_multi.py +29 -0
  67. pylab/templates/q44/alphabet_stock_viz.py +95 -0
  68. pylab/templates/q45/multi_plot.py +65 -0
  69. pylab/templates/q46/dataframe_barchart.py +60 -0
  70. pylab/templates/q47/preprocess_data.py +54 -0
  71. pylab/templates/q48/clean_dirtydata.py +62 -0
  72. pylab/templates/q49/wine_regression.py +169 -0
  73. pylab/templates/q5/phonebook.py +105 -0
  74. pylab/templates/q50/breast_cancer_classifier.py +147 -0
  75. pylab/templates/q51/iris_clustering.py +95 -0
  76. pylab/templates/q52/apriori_groceries.py +88 -0
  77. pylab/templates/q6/calculator.py +67 -0
  78. pylab/templates/q7/session_attendees.py +37 -0
  79. pylab/templates/q8/number_properties.py +68 -0
  80. pylab/templates/q9/greet_people.py +26 -0
  81. python_lab_toolkit-1.0.0.dist-info/LICENSE +21 -0
  82. python_lab_toolkit-1.0.0.dist-info/METADATA +427 -0
  83. python_lab_toolkit-1.0.0.dist-info/RECORD +86 -0
  84. python_lab_toolkit-1.0.0.dist-info/WHEEL +5 -0
  85. python_lab_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
  86. python_lab_toolkit-1.0.0.dist-info/top_level.txt +1 -0
pylab/__init__.py ADDED
@@ -0,0 +1,43 @@
1
+ """python-lab-toolkit (pylab): Beginner-friendly lab generator and toolkit for 52 Python practicals."""
2
+
3
+ __version__ = "1.0.0"
4
+ __author__ = "Python Lab Toolkit Developers"
5
+ __license__ = "MIT"
6
+
7
+ from pylab.datasets import acquire_dataset, list_datasets
8
+ from pylab.environment import run_doctor
9
+ from pylab.errors import (
10
+ DatasetDownloadError,
11
+ DatasetValidationError,
12
+ DependencyMissingError,
13
+ FileCollisionError,
14
+ PyLabError,
15
+ QuestionNotFoundError,
16
+ )
17
+ from pylab.generator import generate_all, generate_category, generate_project
18
+ from pylab.registry import (
19
+ QUESTION_LIST,
20
+ get_categories,
21
+ get_question,
22
+ get_questions_by_category,
23
+ )
24
+
25
+ __all__ = [
26
+ "__version__",
27
+ "generate_project",
28
+ "generate_category",
29
+ "generate_all",
30
+ "get_question",
31
+ "get_categories",
32
+ "get_questions_by_category",
33
+ "acquire_dataset",
34
+ "list_datasets",
35
+ "run_doctor",
36
+ "PyLabError",
37
+ "QuestionNotFoundError",
38
+ "FileCollisionError",
39
+ "DatasetDownloadError",
40
+ "DatasetValidationError",
41
+ "DependencyMissingError",
42
+ "QUESTION_LIST",
43
+ ]
pylab/cli.py ADDED
@@ -0,0 +1,282 @@
1
+ """Beginner-friendly Command Line Interface for python-lab-toolkit."""
2
+
3
+ import argparse
4
+ import os
5
+ import subprocess
6
+ import sys
7
+ from typing import List, Optional
8
+
9
+ from pylab import __version__
10
+ from pylab.datasets import list_datasets
11
+ from pylab.environment import run_doctor
12
+ from pylab.errors import FileCollisionError, PyLabError, QuestionNotFoundError
13
+ from pylab.generator import generate_all, generate_category, generate_project
14
+ from pylab.registry import QUESTION_LIST, get_categories, get_question, get_questions_by_category
15
+
16
+ def format_question_summary(q) -> str:
17
+ deps = f" [Needs: {', '.join(q.dependencies)}]" if q.dependencies else ""
18
+ datasets = f" [Data: {', '.join(q.datasets)}]" if q.datasets else ""
19
+ return f" Q{q.number:<2} : {q.title:<46} ({q.category}){deps}{datasets}"
20
+
21
+ def cmd_list(args) -> int:
22
+ category = getattr(args, "category", None)
23
+ if category:
24
+ norm_cat = category.strip().lower()
25
+ if norm_cat in ("database", "db"):
26
+ norm_cat = "databases"
27
+ questions = get_questions_by_category(norm_cat)
28
+ if not questions:
29
+ avail = ", ".join(get_categories())
30
+ print(f"No questions found for category '{category}'. Available categories: {avail}")
31
+ return 1
32
+ print(f"\nPython Lab Questions in Category '{norm_cat}' ({len(questions)} items):")
33
+ print("=" * 80)
34
+ for q in questions:
35
+ print(format_question_summary(q))
36
+ print("=" * 80)
37
+ return 0
38
+
39
+ print(f"\nPython Lab Toolkit - Complete Question Registry ({len(QUESTION_LIST)} questions):")
40
+ print("=" * 84)
41
+ current_cat = None
42
+ for q in QUESTION_LIST:
43
+ if q.category != current_cat:
44
+ current_cat = q.category
45
+ print(f"\n-- {current_cat.upper()} --")
46
+ print(format_question_summary(q))
47
+ print("=" * 84)
48
+ print("\nTo generate a project, type: pylab q<number>")
49
+ print("Example: pylab q12 or pylab q49")
50
+ print("To auto-generate and immediately run a lab: pylab run q25\n")
51
+ return 0
52
+
53
+ def cmd_datasets(args) -> int:
54
+ data_list = list_datasets()
55
+ print("\nPython Lab Toolkit - Dataset Registry:")
56
+ print("=" * 88)
57
+ print(f"{'Dataset Filename':<26} | {'Used In':<12} | {'Bundled':<10} | {'Description'}")
58
+ print("-" * 88)
59
+ for d in data_list:
60
+ q_str = ", ".join(f"Q{q}" for q in d["questions"])
61
+ b_str = "YES (Offline)" if d["bundled"] else "Remote Only"
62
+ print(f"{d['name']:<26} | {q_str:<12} | {b_str:<10} | {d['description']}")
63
+ print("=" * 88)
64
+ print("All bundled datasets are included inside the package and work without internet access.\n")
65
+ return 0
66
+
67
+ def cmd_generate_question(q_identifier: any, force: bool = False, offline: bool = False, out_dir: str = ".") -> int:
68
+ try:
69
+ res = generate_project(q_identifier, target_base_dir=out_dir, force=force, offline=offline)
70
+ print(res.message)
71
+ return 0
72
+ except FileCollisionError as col_err:
73
+ print(f"\n{col_err}")
74
+ return 1
75
+ except QuestionNotFoundError as q_err:
76
+ print(f"\n{q_err}")
77
+ return 1
78
+ except Exception as e:
79
+ print(f"\nError: {e}")
80
+ return 1
81
+
82
+ def cmd_run(args) -> int:
83
+ q_spec = get_question(args.question)
84
+ if not q_spec:
85
+ print(f"Question '{args.question}' was not recognized.")
86
+ return 1
87
+
88
+ project_dir = os.path.join(args.output_dir, q_spec.slug)
89
+ if not os.path.isdir(project_dir):
90
+ print(f"Project for Question {q_spec.number} not found locally. Auto-generating now...")
91
+ generate_project(q_spec.number, target_base_dir=args.output_dir, offline=args.offline)
92
+
93
+ entry_file = os.path.join(project_dir, q_spec.entry_point)
94
+ if not os.path.isfile(entry_file):
95
+ print(f"Entry script '{entry_file}' not found.")
96
+ return 1
97
+
98
+ print(f"Executing Question {q_spec.number} ({q_spec.title}) automatically...\n")
99
+ proc = subprocess.run([sys.executable, q_spec.entry_point], cwd=project_dir)
100
+ return proc.returncode
101
+
102
+ def cmd_category(args) -> int:
103
+ category = args.name.strip().lower()
104
+ if category in ("database", "db"):
105
+ category = "databases"
106
+ questions = get_questions_by_category(category)
107
+ if not questions:
108
+ avail = ", ".join(get_categories())
109
+ print(f"Unknown category '{category}'. Available categories: {avail}")
110
+ return 1
111
+
112
+ print(f"Generating all {len(questions)} questions in category '{category}'...")
113
+ success_count = 0
114
+ for q in questions:
115
+ try:
116
+ res = generate_project(q.number, target_base_dir=args.output_dir, force=args.force, offline=args.offline)
117
+ print(f" [OK] Question {q.number}: {res.project_dir}/")
118
+ success_count += 1
119
+ except FileCollisionError:
120
+ print(f" [SKIP] Question {q.number} ({q.slug}) already exists. Use --force to replace.")
121
+ except Exception as err:
122
+ print(f" [FAIL] Question {q.number}: {err}")
123
+ print(f"\nCompleted: {success_count} of {len(questions)} projects generated.")
124
+ return 0
125
+
126
+ def cmd_all(args) -> int:
127
+ total_q = len(QUESTION_LIST)
128
+ if not args.yes:
129
+ print(f"Generating all {total_q} lab questions will create {total_q} dedicated project directories.")
130
+ answer = input("Do you wish to continue? (y/N): ").strip().lower()
131
+ if answer not in ("y", "yes"):
132
+ print("Operation cancelled.")
133
+ return 0
134
+
135
+ print(f"\nGenerating all {total_q} questions...")
136
+ success_count = 0
137
+ skipped_count = 0
138
+ for q in QUESTION_LIST:
139
+ try:
140
+ res = generate_project(q.number, target_base_dir=args.output_dir, force=args.force, offline=args.offline)
141
+ print(f" [OK] Q{q.number:<2} -> {res.project_dir}/")
142
+ success_count += 1
143
+ except FileCollisionError:
144
+ print(f" [SKIP] Q{q.number:<2} ({q.slug}) exists (use --force to overwrite)")
145
+ skipped_count += 1
146
+ except Exception as err:
147
+ print(f" [FAIL] Q{q.number:<2}: {err}")
148
+
149
+ print(f"\nSummary: {success_count} generated, {skipped_count} skipped.")
150
+ return 0
151
+
152
+ def cmd_install_deps(args) -> int:
153
+ q_spec = get_question(args.question)
154
+ if not q_spec:
155
+ print(f"Question '{args.question}' not recognized.")
156
+ return 1
157
+
158
+ if not q_spec.dependencies:
159
+ print(f"Question {q_spec.number} requires only Python standard library. No additional packages needed.")
160
+ return 0
161
+
162
+ deps = q_spec.dependencies
163
+ print(f"Question {q_spec.number} ({q_spec.title}) requires: {', '.join(deps)}")
164
+ if not args.yes:
165
+ ans = input(f"Install {', '.join(deps)} using pip now? (y/N): ").strip().lower()
166
+ if ans not in ("y", "yes"):
167
+ print("Installation cancelled.")
168
+ return 0
169
+
170
+ cmd = [sys.executable, "-m", "pip", "install"] + deps
171
+ print(f"Running: {' '.join(cmd)}")
172
+ result = subprocess.run(cmd)
173
+ return result.returncode
174
+
175
+ def build_parser() -> argparse.ArgumentParser:
176
+ parser = argparse.ArgumentParser(
177
+ prog="pylab",
178
+ description="python-lab-toolkit: Beginner-friendly CLI for 52 Python lab solutions with automated datasets.",
179
+ formatter_class=argparse.RawDescriptionHelpFormatter,
180
+ )
181
+ parser.add_argument("-v", "--version", action="store_true", help="Show package version and exit")
182
+
183
+ subparsers = parser.add_subparsers(dest="command", help="Available subcommands")
184
+
185
+ list_p = subparsers.add_parser("list", help="List all 52 questions or filter by category")
186
+ list_p.add_argument("--category", "-c", type=str, help="Filter by category (e.g. numpy, pandas, databases, machine-learning)")
187
+
188
+ subparsers.add_parser("doctor", help="Check Python version, write permissions, and optional dependencies")
189
+ subparsers.add_parser("datasets", help="Display all registered and bundled datasets")
190
+ subparsers.add_parser("version", help="Show version information")
191
+
192
+ run_p = subparsers.add_parser("run", help="Auto-generate and execute a lab question immediately")
193
+ run_p.add_argument("question", type=str, help="Question number or identifier (e.g. q25, q26, or 25)")
194
+ run_p.add_argument("--offline", action="store_true", help="Force offline bundled datasets")
195
+ run_p.add_argument("--output-dir", "-o", default=".", help="Directory where project is located or generated")
196
+
197
+ cat_p = subparsers.add_parser("category", help="Generate all questions in a specific category")
198
+ cat_p.add_argument("name", type=str, help="Category name (e.g. numpy, pandas, databases, machine-learning)")
199
+ cat_p.add_argument("--force", "-f", action="store_true", help="Overwrite existing project files")
200
+ cat_p.add_argument("--offline", action="store_true", help="Force offline bundled datasets")
201
+ cat_p.add_argument("--output-dir", "-o", default=".", help="Directory where projects will be generated")
202
+
203
+ all_p = subparsers.add_parser("all", help="Generate all 52 lab questions")
204
+ all_p.add_argument("--yes", "-y", action="store_true", help="Confirm generation without interactive prompt")
205
+ all_p.add_argument("--force", "-f", action="store_true", help="Overwrite existing project files")
206
+ all_p.add_argument("--offline", action="store_true", help="Force offline bundled datasets")
207
+ all_p.add_argument("--output-dir", "-o", default=".", help="Directory where projects will be generated")
208
+
209
+ deps_p = subparsers.add_parser("install-deps", help="Install third-party dependencies required for a question")
210
+ deps_p.add_argument("question", type=str, help="Question number or identifier (e.g. q49 or 49)")
211
+ deps_p.add_argument("--yes", "-y", action="store_true", help="Confirm installation without prompting")
212
+
213
+ gen_p = subparsers.add_parser("generate", help="Generate project files for a specific question")
214
+ gen_p.add_argument("question", type=str, help="Question number (1-52)")
215
+ gen_p.add_argument("--force", "-f", action="store_true", help="Overwrite existing project files")
216
+ gen_p.add_argument("--offline", action="store_true", help="Force offline bundled datasets")
217
+ gen_p.add_argument("--output-dir", "-o", default=".", help="Directory where project will be generated")
218
+
219
+ return parser
220
+
221
+ def main(argv: Optional[List[str]] = None) -> int:
222
+ if argv is None:
223
+ argv = sys.argv[1:]
224
+
225
+ if not argv:
226
+ parser = build_parser()
227
+ parser.print_help()
228
+ return 0
229
+
230
+ first_arg = argv[0].strip().lower()
231
+
232
+ if first_arg in ("--version", "-v", "version"):
233
+ print(f"python-lab-toolkit (pylab) v{__version__}")
234
+ return 0
235
+
236
+ if first_arg.startswith("q") and first_arg[1:].isdigit():
237
+ q_num = int(first_arg[1:])
238
+ gen_parser = argparse.ArgumentParser(prog=f"pylab {first_arg}")
239
+ gen_parser.add_argument("--force", "-f", action="store_true", help="Overwrite existing files")
240
+ gen_parser.add_argument("--offline", action="store_true", help="Force offline bundled datasets")
241
+ gen_parser.add_argument("--output-dir", "-o", default=".", help="Output directory")
242
+ parsed_opts = gen_parser.parse_args(argv[1:])
243
+ return cmd_generate_question(
244
+ q_num,
245
+ force=parsed_opts.force,
246
+ offline=parsed_opts.offline,
247
+ out_dir=parsed_opts.output_dir,
248
+ )
249
+
250
+ parser = build_parser()
251
+ args = parser.parse_args(argv)
252
+
253
+ if args.version or args.command == "version":
254
+ print(f"python-lab-toolkit (pylab) v{__version__}")
255
+ return 0
256
+ elif args.command == "list":
257
+ return cmd_list(args)
258
+ elif args.command == "doctor":
259
+ return run_doctor()
260
+ elif args.command == "datasets":
261
+ return cmd_datasets(args)
262
+ elif args.command == "run":
263
+ return cmd_run(args)
264
+ elif args.command == "category":
265
+ return cmd_category(args)
266
+ elif args.command == "all":
267
+ return cmd_all(args)
268
+ elif args.command == "install-deps":
269
+ return cmd_install_deps(args)
270
+ elif args.command == "generate":
271
+ return cmd_generate_question(
272
+ args.question,
273
+ force=args.force,
274
+ offline=args.offline,
275
+ out_dir=args.output_dir,
276
+ )
277
+ else:
278
+ parser.print_help()
279
+ return 0
280
+
281
+ if __name__ == "__main__":
282
+ sys.exit(main())
pylab/data/Data.csv ADDED
@@ -0,0 +1,11 @@
1
+ Country,Age,Salary,Purchased
2
+ France,44,72000,No
3
+ Spain,27,48000,Yes
4
+ Germany,30,54000,No
5
+ Spain,38,61000,No
6
+ Germany,40,,Yes
7
+ France,35,58000,Yes
8
+ Spain,,52000,No
9
+ France,48,79000,Yes
10
+ Germany,50,83000,No
11
+ France,37,67000,Yes
@@ -0,0 +1,143 @@
1
+ Date,Open,High,Low,Close,Adj Close,Volume
2
+ 2020-04-01,1203.0,1240.43,1194.27,1232.73,1232.73,1707528
3
+ 2020-04-02,1224.01,1226.28,1203.44,1212.64,1212.64,2123658
4
+ 2020-04-03,1216.8,1219.57,1189.32,1192.2,1192.2,1331755
5
+ 2020-04-06,1183.62,1210.99,1172.92,1205.9,1205.9,2098574
6
+ 2020-04-07,1210.37,1228.5,1200.88,1215.03,1215.03,2219204
7
+ 2020-04-08,1221.18,1243.81,1217.92,1239.33,1239.33,3007959
8
+ 2020-04-09,1237.55,1250.78,1229.34,1232.04,1232.04,1612794
9
+ 2020-04-10,1236.6,1249.01,1211.51,1214.93,1214.93,2003587
10
+ 2020-04-13,1213.9,1221.38,1193.74,1199.36,1199.36,2247764
11
+ 2020-04-14,1190.87,1226.47,1177.74,1213.97,1213.97,1610658
12
+ 2020-04-15,1223.96,1236.83,1187.14,1201.74,1201.74,2191447
13
+ 2020-04-16,1201.45,1206.23,1178.39,1185.6,1185.6,1445934
14
+ 2020-04-17,1175.64,1182.72,1145.66,1159.7,1159.7,3108443
15
+ 2020-04-20,1163.63,1175.13,1142.14,1154.32,1154.32,3241247
16
+ 2020-04-21,1150.25,1164.84,1124.23,1133.76,1133.76,3474131
17
+ 2020-04-22,1130.03,1132.68,1100.18,1108.38,1108.38,3427704
18
+ 2020-04-23,1117.6,1120.64,1096.84,1101.26,1101.26,1485048
19
+ 2020-04-24,1095.96,1111.66,1082.39,1108.1,1108.1,2232702
20
+ 2020-04-27,1098.89,1108.8,1088.34,1105.73,1105.73,3392709
21
+ 2020-04-28,1100.95,1111.66,1087.27,1093.35,1093.35,2314068
22
+ 2020-04-29,1096.78,1102.68,1087.44,1093.55,1093.55,1504267
23
+ 2020-04-30,1095.97,1105.29,1068.18,1071.48,1071.48,3455002
24
+ 2020-05-01,1066.78,1080.91,1040.05,1053.5,1053.5,2224603
25
+ 2020-05-04,1046.65,1059.49,1030.82,1041.97,1041.97,3418538
26
+ 2020-05-05,1048.31,1054.2,1013.12,1023.74,1023.74,1763257
27
+ 2020-05-06,1031.53,1043.18,1017.06,1021.08,1021.08,2381771
28
+ 2020-05-07,1025.43,1038.35,1015.18,1033.7,1033.7,2307228
29
+ 2020-05-08,1028.72,1045.33,1026.06,1031.52,1031.52,2976605
30
+ 2020-05-11,1022.4,1049.35,1018.7,1043.01,1043.01,2298720
31
+ 2020-05-12,1041.85,1053.02,1016.45,1025.74,1025.74,1669233
32
+ 2020-05-13,1033.4,1047.15,1003.45,1012.54,1012.54,2748604
33
+ 2020-05-14,1005.5,1016.2,999.49,1012.54,1012.54,1367331
34
+ 2020-05-15,1006.74,1036.42,1003.4,1031.18,1031.18,2904470
35
+ 2020-05-18,1036.17,1078.76,1031.09,1064.73,1064.73,1881581
36
+ 2020-05-19,1070.95,1113.1,1068.63,1099.64,1099.64,2593286
37
+ 2020-05-20,1097.87,1126.61,1086.31,1115.9,1115.9,2240888
38
+ 2020-05-21,1121.65,1125.06,1097.98,1111.32,1111.32,3174217
39
+ 2020-05-22,1117.65,1125.63,1098.91,1104.88,1104.88,2154604
40
+ 2020-05-25,1108.08,1115.26,1089.72,1095.34,1095.34,1491171
41
+ 2020-05-26,1090.92,1129.44,1083.72,1119.1,1119.1,3449051
42
+ 2020-05-27,1109.65,1123.05,1097.46,1102.86,1102.86,2313446
43
+ 2020-05-28,1104.79,1111.28,1069.67,1081.89,1081.89,3030368
44
+ 2020-05-29,1082.12,1097.47,1072.62,1090.46,1090.46,2268383
45
+ 2020-06-01,1089.18,1097.94,1054.14,1066.62,1066.62,2026425
46
+ 2020-06-02,1058.02,1068.66,1046.76,1053.05,1053.05,2516657
47
+ 2020-06-03,1045.54,1070.73,1036.95,1057.03,1057.03,2912924
48
+ 2020-06-04,1060.97,1070.18,1049.42,1053.91,1053.91,2790250
49
+ 2020-06-05,1061.97,1084.22,1056.06,1074.22,1074.22,3498215
50
+ 2020-06-08,1070.3,1095.88,1058.09,1091.15,1091.15,2551611
51
+ 2020-06-09,1089.99,1095.34,1081.84,1090.56,1090.56,1911737
52
+ 2020-06-10,1086.24,1108.11,1076.19,1097.48,1097.48,1591694
53
+ 2020-06-11,1102.5,1133.26,1097.58,1122.51,1122.51,2035211
54
+ 2020-06-12,1113.43,1128.22,1086.58,1096.53,1096.53,1505463
55
+ 2020-06-15,1104.25,1113.78,1092.91,1104.3,1104.3,2810522
56
+ 2020-06-16,1099.18,1111.9,1097.11,1101.37,1101.37,1647059
57
+ 2020-06-17,1095.75,1126.01,1084.7,1113.56,1113.56,3148463
58
+ 2020-06-18,1108.54,1121.57,1078.37,1086.3,1086.3,3148854
59
+ 2020-06-19,1096.06,1117.52,1081.71,1107.78,1107.78,3056287
60
+ 2020-06-22,1112.17,1129.43,1099.37,1120.87,1120.87,3497941
61
+ 2020-06-23,1114.05,1127.25,1105.73,1113.58,1113.58,2236998
62
+ 2020-06-24,1109.13,1142.43,1100.83,1130.32,1130.32,2203469
63
+ 2020-06-25,1121.87,1127.58,1106.44,1111.97,1111.97,2540959
64
+ 2020-06-26,1103.58,1131.66,1096.6,1127.7,1127.7,1840911
65
+ 2020-06-29,1118.98,1140.13,1109.93,1132.83,1132.83,2943883
66
+ 2020-06-30,1139.49,1146.55,1105.9,1117.91,1117.91,1281922
67
+ 2020-07-01,1123.22,1152.28,1121.14,1145.34,1145.34,2675383
68
+ 2020-07-02,1143.14,1156.73,1121.7,1134.56,1134.56,3457460
69
+ 2020-07-03,1135.48,1161.43,1130.61,1151.59,1151.59,2120321
70
+ 2020-07-06,1151.3,1158.36,1130.61,1141.31,1141.31,2895827
71
+ 2020-07-07,1148.12,1176.9,1133.37,1162.95,1162.95,3440276
72
+ 2020-07-08,1160.83,1170.17,1134.96,1137.31,1137.31,2997732
73
+ 2020-07-09,1136.54,1139.19,1112.07,1119.0,1119.0,2087767
74
+ 2020-07-10,1115.75,1129.2,1110.13,1115.76,1115.76,2968171
75
+ 2020-07-13,1107.4,1109.65,1087.26,1096.27,1096.27,2667840
76
+ 2020-07-14,1087.64,1102.08,1072.45,1074.97,1074.97,1330149
77
+ 2020-07-15,1068.96,1098.45,1064.98,1096.19,1096.19,1729409
78
+ 2020-07-16,1088.48,1103.85,1080.43,1089.53,1089.53,2274763
79
+ 2020-07-17,1082.89,1109.96,1071.17,1100.07,1100.07,1680385
80
+ 2020-07-20,1093.35,1117.17,1083.83,1111.13,1111.13,2508443
81
+ 2020-07-21,1119.29,1132.84,1105.05,1125.96,1125.96,2031855
82
+ 2020-07-22,1129.77,1139.92,1105.63,1108.95,1108.95,2464929
83
+ 2020-07-23,1110.96,1136.3,1096.17,1132.73,1132.73,1372256
84
+ 2020-07-24,1131.3,1138.12,1116.82,1125.4,1125.4,2631227
85
+ 2020-07-27,1123.8,1132.17,1091.86,1099.5,1099.5,2719126
86
+ 2020-07-28,1106.07,1127.23,1098.41,1116.03,1116.03,3388364
87
+ 2020-07-29,1111.43,1152.04,1102.43,1139.53,1139.53,3227935
88
+ 2020-07-30,1146.04,1156.31,1139.85,1146.61,1146.61,2229681
89
+ 2020-07-31,1138.34,1172.49,1133.17,1159.03,1159.03,3149128
90
+ 2020-08-03,1162.39,1175.1,1153.96,1168.73,1168.73,2563208
91
+ 2020-08-04,1162.97,1175.34,1141.55,1147.97,1147.97,2358754
92
+ 2020-08-05,1148.3,1158.35,1143.16,1153.87,1153.87,2904683
93
+ 2020-08-06,1159.03,1171.88,1148.63,1160.9,1160.9,3258653
94
+ 2020-08-07,1151.24,1157.07,1143.63,1150.89,1150.89,2220495
95
+ 2020-08-10,1152.52,1160.67,1135.46,1144.36,1144.36,2984692
96
+ 2020-08-11,1145.37,1181.75,1137.47,1175.18,1175.18,2486070
97
+ 2020-08-12,1167.59,1172.09,1152.87,1156.42,1156.42,3447576
98
+ 2020-08-13,1160.22,1192.01,1148.62,1187.52,1187.52,2359723
99
+ 2020-08-14,1197.05,1220.72,1191.37,1211.9,1211.9,1621637
100
+ 2020-08-17,1207.82,1235.3,1201.89,1228.61,1228.61,3440324
101
+ 2020-08-18,1219.52,1222.23,1195.68,1201.48,1201.48,1729654
102
+ 2020-08-19,1206.54,1219.95,1204.38,1216.62,1216.62,2392605
103
+ 2020-08-20,1215.43,1220.65,1212.76,1216.25,1216.25,3203741
104
+ 2020-08-21,1207.56,1215.95,1179.33,1188.83,1188.83,1424852
105
+ 2020-08-24,1195.05,1209.39,1175.28,1178.39,1178.39,2240988
106
+ 2020-08-25,1183.68,1193.56,1152.91,1165.19,1165.19,2146600
107
+ 2020-08-26,1162.8,1194.27,1156.93,1180.46,1180.46,2998642
108
+ 2020-08-27,1182.88,1192.81,1163.06,1174.68,1174.68,2071525
109
+ 2020-08-28,1169.97,1182.43,1164.85,1179.37,1179.37,1514844
110
+ 2020-08-31,1177.54,1188.5,1153.04,1161.15,1161.15,1336901
111
+ 2020-09-01,1165.29,1176.43,1145.12,1153.02,1153.02,2179050
112
+ 2020-09-02,1158.78,1194.73,1148.18,1184.6,1184.6,2029713
113
+ 2020-09-03,1185.49,1195.91,1170.06,1183.87,1183.87,1796582
114
+ 2020-09-04,1177.19,1183.19,1144.38,1156.12,1156.12,2410520
115
+ 2020-09-07,1155.49,1161.44,1147.41,1154.64,1154.64,2341883
116
+ 2020-09-08,1154.52,1160.1,1152.0,1157.05,1157.05,3012059
117
+ 2020-09-09,1159.12,1176.86,1154.14,1174.52,1174.52,1287012
118
+ 2020-09-10,1177.97,1213.45,1175.45,1207.95,1207.95,1934803
119
+ 2020-09-11,1210.98,1225.77,1206.62,1211.86,1211.86,3028234
120
+ 2020-09-14,1211.69,1224.79,1205.17,1221.6,1221.6,2597996
121
+ 2020-09-15,1213.69,1217.78,1199.0,1206.35,1206.35,3278147
122
+ 2020-09-16,1215.25,1227.83,1196.95,1206.1,1206.1,3107678
123
+ 2020-09-17,1201.15,1204.66,1168.95,1180.99,1180.99,3358373
124
+ 2020-09-18,1171.01,1204.68,1163.0,1191.38,1191.38,1427348
125
+ 2020-09-21,1188.62,1200.45,1163.81,1173.94,1173.94,1416475
126
+ 2020-09-22,1174.92,1188.98,1153.42,1161.12,1161.12,3233028
127
+ 2020-09-23,1170.58,1180.5,1147.15,1152.26,1152.26,1864286
128
+ 2020-09-24,1142.53,1149.83,1129.7,1134.62,1134.62,1675890
129
+ 2020-09-25,1126.97,1140.17,1118.49,1127.35,1127.35,2424156
130
+ 2020-09-28,1122.82,1138.66,1108.08,1125.81,1125.81,2222281
131
+ 2020-09-29,1118.7,1123.3,1108.91,1118.82,1118.82,1772557
132
+ 2020-09-30,1114.34,1149.13,1106.95,1136.86,1136.86,3329606
133
+ 2020-10-01,1126.91,1138.35,1103.71,1116.6,1116.6,3253700
134
+ 2020-10-02,1115.53,1146.42,1109.21,1138.12,1138.12,3479310
135
+ 2020-10-05,1146.78,1160.08,1127.78,1142.53,1142.53,2201623
136
+ 2020-10-06,1137.2,1155.73,1134.63,1143.65,1143.65,3183806
137
+ 2020-10-07,1149.88,1170.69,1139.25,1163.67,1163.67,1837975
138
+ 2020-10-08,1154.41,1165.18,1144.74,1156.65,1156.65,1620959
139
+ 2020-10-09,1155.46,1187.38,1147.52,1178.54,1178.54,1804631
140
+ 2020-10-12,1181.64,1185.65,1171.09,1179.19,1179.19,2311586
141
+ 2020-10-13,1183.04,1193.49,1163.59,1176.66,1176.66,3438174
142
+ 2020-10-14,1172.99,1184.33,1157.02,1168.89,1168.89,3469185
143
+ 2020-10-15,1160.26,1170.47,1123.26,1137.23,1137.23,2154146