studium 0.14.16

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of studium might be problematic. Click here for more details.

Files changed (883) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2987 -0
  3. data/bin/ask_exam_question +7 -0
  4. data/bin/check_description_of_these_lectures +7 -0
  5. data/bin/curriculum_module_displayer +7 -0
  6. data/bin/cycle +7 -0
  7. data/bin/d10 +7 -0
  8. data/bin/d100 +7 -0
  9. data/bin/d15 +7 -0
  10. data/bin/d20 +7 -0
  11. data/bin/d25 +7 -0
  12. data/bin/d3 +7 -0
  13. data/bin/d30 +7 -0
  14. data/bin/d5 +7 -0
  15. data/bin/determine_curricula +7 -0
  16. data/bin/display_lecture_url +7 -0
  17. data/bin/exam_registration_at +7 -0
  18. data/bin/exam_statistics +7 -0
  19. data/bin/exams_per_month +9 -0
  20. data/bin/finished_exams_at_this_university +7 -0
  21. data/bin/flashcards +7 -0
  22. data/bin/from_curriculum_id_to_university +9 -0
  23. data/bin/location_to_this_exam_topic.rb +7 -0
  24. data/bin/mandatory_continuous_assessment +7 -0
  25. data/bin/mandatory_upcoming_courses +10 -0
  26. data/bin/n_ECTS +7 -0
  27. data/bin/n_exam_questions_already_answered +16 -0
  28. data/bin/nquestions +7 -0
  29. data/bin/nsolved +7 -0
  30. data/bin/open_last_exam_question_asked_file +7 -0
  31. data/bin/passed_exams +7 -0
  32. data/bin/passed_pr/303/274fungsimmanente_courses +7 -0
  33. data/bin/pdf_for +7 -0
  34. data/bin/random_exam_topic +7 -0
  35. data/bin/report_solved_topics +7 -0
  36. data/bin/return_n_ects_from_this_file +7 -0
  37. data/bin/search_for_n_ects +7 -0
  38. data/bin/show_lectures_on_the_commandline +7 -0
  39. data/bin/show_themes +7 -0
  40. data/bin/solved +9 -0
  41. data/bin/solved_ects +7 -0
  42. data/bin/studienkennzahl +7 -0
  43. data/bin/studium +7 -0
  44. data/bin/studium_skeleton +7 -0
  45. data/bin/ufind +7 -0
  46. data/bin/upcoming_exams +7 -0
  47. data/bin/week_parser +7 -0
  48. data/doc/ECTS_CONSIDERATIONS.md +82 -0
  49. data/doc/HOW_TO_DETERMINE_WHICH_PART_IS_THE_QUESTION_AND_WHICH_PART_IS_THE_ANSWER.md +44 -0
  50. data/doc/README.gen +2947 -0
  51. data/doc/SQL_database_specification.md +46 -0
  52. data/doc/deprecated_components.md +24 -0
  53. data/doc/documentation_for_the_file_lecture_information.md +311 -0
  54. data/doc/elegant_colours.md +21 -0
  55. data/doc/statistics/yearly_statistics.md +5 -0
  56. data/doc/todo/todo_for_the_graphical_parts_of_the_studium_gem_including_www_related_aspects.md +32 -0
  57. data/doc/todo/todo_for_the_studium_gem.md +58 -0
  58. data/img/STUDIES.png +0 -0
  59. data/lib/studium/autoinclude.rb +7 -0
  60. data/lib/studium/base/base.rb +3054 -0
  61. data/lib/studium/base/prototype.rb +592 -0
  62. data/lib/studium/c/README.md +2 -0
  63. data/lib/studium/c/a.out +0 -0
  64. data/lib/studium/c/obtain_random_entry.c +11 -0
  65. data/lib/studium/check_and_sanitize/README.md +15 -0
  66. data/lib/studium/check_and_sanitize/check_curriculum_for_correct_separation_of_bachelor_and_master.rb +141 -0
  67. data/lib/studium/check_and_sanitize/check_for_all_exam_topics_being_registered.rb +118 -0
  68. data/lib/studium/check_and_sanitize/check_for_correct_themes_of_each_course.rb +100 -0
  69. data/lib/studium/check_and_sanitize/check_for_existing_description_of_this_lecture.rb +191 -0
  70. data/lib/studium/check_and_sanitize/check_important_exams.rb +113 -0
  71. data/lib/studium/check_and_sanitize/check_the_lecture_information_file.rb +163 -0
  72. data/lib/studium/check_and_sanitize/find_duplicate_lectures.rb +124 -0
  73. data/lib/studium/check_and_sanitize/missing_priority_entry.rb +44 -0
  74. data/lib/studium/check_and_sanitize/sanitize_lecture_information.rb +428 -0
  75. data/lib/studium/check_and_sanitize/sanitize_this_string_containing_the_lva_dates.rb +79 -0
  76. data/lib/studium/colours/colours.rb +572 -0
  77. data/lib/studium/colours/sfancy.rb +46 -0
  78. data/lib/studium/colours/sfile.rb +35 -0
  79. data/lib/studium/colours/simp.rb +40 -0
  80. data/lib/studium/colours/use_colours.rb +39 -0
  81. data/lib/studium/colours/use_this_colour_for_exam_questions_and_exam_answers.rb +80 -0
  82. data/lib/studium/commandline/commandline.rb +932 -0
  83. data/lib/studium/commandline/menu.rb +906 -0
  84. data/lib/studium/constants/colours.rb +14 -0
  85. data/lib/studium/constants/constants.rb +1708 -0
  86. data/lib/studium/constants/image_constants.rb +271 -0
  87. data/lib/studium/constants/regexes.rb +44 -0
  88. data/lib/studium/constants/web_constants.rb +28 -0
  89. data/lib/studium/css/project.css +267 -0
  90. data/lib/studium/curricula/curriculum.rb +210 -0
  91. data/lib/studium/curricula/curriculum_as_string.rb +280 -0
  92. data/lib/studium/curricula/curriculum_module_displayer/constants.rb +33 -0
  93. data/lib/studium/curricula/curriculum_module_displayer/curriculum_module_displayer.rb +417 -0
  94. data/lib/studium/curricula/curriculum_module_displayer/initialize.rb +25 -0
  95. data/lib/studium/curricula/curriculum_module_displayer/menu.rb +45 -0
  96. data/lib/studium/curricula/curriculum_module_displayer/reset.rb +74 -0
  97. data/lib/studium/curricula/curriculum_module_displayer/run.rb +20 -0
  98. data/lib/studium/curricula/curriculum_module_displayer/set_use_this_curriculum.rb +93 -0
  99. data/lib/studium/curricula/curriculum_module_displayer/show_and_report.rb +190 -0
  100. data/lib/studium/curricula/determine_curricula/constants.rb +11 -0
  101. data/lib/studium/curricula/determine_curricula/determine_curricula.rb +36 -0
  102. data/lib/studium/curricula/determine_curricula/help.rb +39 -0
  103. data/lib/studium/curricula/determine_curricula/initialize.rb +48 -0
  104. data/lib/studium/curricula/determine_curricula/menu.rb +151 -0
  105. data/lib/studium/curricula/determine_curricula/misc.rb +403 -0
  106. data/lib/studium/curricula/determine_curricula/report.rb +143 -0
  107. data/lib/studium/curricula/determine_curricula/reset.rb +59 -0
  108. data/lib/studium/curricula/determine_curricula/run.rb +19 -0
  109. data/lib/studium/curricula/determine_elective_courses_in_this_curriculum.rb +112 -0
  110. data/lib/studium/curricula/display_bachelor_curricula.rb +90 -0
  111. data/lib/studium/curricula/handle_curricula/README.md +9 -0
  112. data/lib/studium/curricula/handle_curricula/handle_curricula.rb +179 -0
  113. data/lib/studium/curricula/handle_curricula/misc.rb +705 -0
  114. data/lib/studium/curricula/mitteilungsbl/303/244tter/mitteilungsbl/303/244tter.rb +323 -0
  115. data/lib/studium/curricula/modules/display_on_the_commandline.rb +319 -0
  116. data/lib/studium/curricula/modules/return_n_ects_in_this_module.rb +75 -0
  117. data/lib/studium/curricula/n_percent_solved_in_this_curriculum.rb +75 -0
  118. data/lib/studium/curricula/prepare_individual_curriculum.rb +304 -0
  119. data/lib/studium/curricula/random_curriculum_creator/random_curriculum_creator.rb +163 -0
  120. data/lib/studium/curricula/show_lectures_of_this_curriculum.rb +114 -0
  121. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/constants.rb +11 -0
  122. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/initialize.rb +27 -0
  123. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/menu.rb +35 -0
  124. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/misc.rb +264 -0
  125. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/report.rb +163 -0
  126. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/reset.rb +64 -0
  127. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/show_lectures_of_this_curriculum_id.rb +38 -0
  128. data/lib/studium/curricula/show_solved_percentage_among_the_registered_curricula.rb +87 -0
  129. data/lib/studium/curricula/sorted_individual_curricula.rb +121 -0
  130. data/lib/studium/ects/boku_ects_splitter.rb +128 -0
  131. data/lib/studium/ects/ects_per_university.rb +179 -0
  132. data/lib/studium/ects/ects_scanner.rb +141 -0
  133. data/lib/studium/ects/ects_to_university_parser.rb +142 -0
  134. data/lib/studium/ects/last_entry_is_curriculum.rb +150 -0
  135. data/lib/studium/ects/n_ects_in_these_lectures.rb +196 -0
  136. data/lib/studium/ects/n_ects_points_in_mandatory_presence_courses.rb +50 -0
  137. data/lib/studium/ects/return_n_ects_from_this_file.rb +59 -0
  138. data/lib/studium/ects/return_n_ects_from_this_url.rb +196 -0
  139. data/lib/studium/ects/search_for_n_ects.rb +614 -0
  140. data/lib/studium/ects/show_completed_ects_in_all_curricula.rb +191 -0
  141. data/lib/studium/ects/show_passed_credits_per_curriculum.rb +276 -0
  142. data/lib/studium/ects/simple_total_ects_points.rb +135 -0
  143. data/lib/studium/ects/solved_ects/constants.rb +19 -0
  144. data/lib/studium/ects/solved_ects/reset.rb +51 -0
  145. data/lib/studium/ects/solved_ects/solved_ects.rb +325 -0
  146. data/lib/studium/ects/solved_ects_per_university/reset.rb +25 -0
  147. data/lib/studium/ects/solved_ects_per_university/solved_ects_per_university.rb +106 -0
  148. data/lib/studium/ects/still_missing.rb +129 -0
  149. data/lib/studium/ects/sum_of_ects.rb +144 -0
  150. data/lib/studium/encoding/encoding.rb +108 -0
  151. data/lib/studium/exam_topics/RNAi_siRNA_and_miRNA +100 -0
  152. data/lib/studium/exam_topics/abfall_als_ressource +86 -0
  153. data/lib/studium/exam_topics/advanced_biochemistry +793 -0
  154. data/lib/studium/exam_topics/advanced_biotechnology +225 -0
  155. data/lib/studium/exam_topics/advanced_cellbiology +105 -0
  156. data/lib/studium/exam_topics/advanced_chemistry +518 -0
  157. data/lib/studium/exam_topics/advanced_microbiology +44 -0
  158. data/lib/studium/exam_topics/advanced_topics_in_plant_sciences +85 -0
  159. data/lib/studium/exam_topics/advanced_virology +229 -0
  160. data/lib/studium/exam_topics/ageing +117 -0
  161. data/lib/studium/exam_topics/agrar_ecology +63 -0
  162. data/lib/studium/exam_topics/agrarmarkt +74 -0
  163. data/lib/studium/exam_topics/agrarphysik +35 -0
  164. data/lib/studium/exam_topics/alcohols +29 -0
  165. data/lib/studium/exam_topics/algorithms +59 -0
  166. data/lib/studium/exam_topics/allergie +76 -0
  167. data/lib/studium/exam_topics/allgemeine_genetik +1006 -0
  168. data/lib/studium/exam_topics/allgemeine_mikrobiologie +977 -0
  169. data/lib/studium/exam_topics/aminoacids +447 -0
  170. data/lib/studium/exam_topics/analytische_chemie_1 +132 -0
  171. data/lib/studium/exam_topics/analytische_chemie_2 +31 -0
  172. data/lib/studium/exam_topics/anatomie +292 -0
  173. data/lib/studium/exam_topics/anorganische_chemie +323 -0
  174. data/lib/studium/exam_topics/anthropologie +117 -0
  175. data/lib/studium/exam_topics/antibodies_and_antigens +770 -0
  176. data/lib/studium/exam_topics/apoptosis +35 -0
  177. data/lib/studium/exam_topics/archaea +95 -0
  178. data/lib/studium/exam_topics/architecture +8 -0
  179. data/lib/studium/exam_topics/artificial_intelligence +85 -0
  180. data/lib/studium/exam_topics/atomemissionsspektrometrie +6 -0
  181. data/lib/studium/exam_topics/audio +11 -0
  182. data/lib/studium/exam_topics/bacteriophages +243 -0
  183. data/lib/studium/exam_topics/basic_biochemistry +1005 -0
  184. data/lib/studium/exam_topics/basic_biotechnology +1004 -0
  185. data/lib/studium/exam_topics/basic_chemistry +1007 -0
  186. data/lib/studium/exam_topics/basic_virology +1010 -0
  187. data/lib/studium/exam_topics/bauwesen +6 -0
  188. data/lib/studium/exam_topics/betriebssysteme +126 -0
  189. data/lib/studium/exam_topics/betriebswirtschaftslehre +29 -0
  190. data/lib/studium/exam_topics/bioanalytik_und_biosensoren +389 -0
  191. data/lib/studium/exam_topics/biochips +79 -0
  192. data/lib/studium/exam_topics/bioelektrochemie +57 -0
  193. data/lib/studium/exam_topics/biofilms +24 -0
  194. data/lib/studium/exam_topics/bioinformatics +507 -0
  195. data/lib/studium/exam_topics/biological_therapeutics +155 -0
  196. data/lib/studium/exam_topics/biologie +139 -0
  197. data/lib/studium/exam_topics/biomarkers +135 -0
  198. data/lib/studium/exam_topics/biomaterials +89 -0
  199. data/lib/studium/exam_topics/biomembranes +6 -0
  200. data/lib/studium/exam_topics/bionik +65 -0
  201. data/lib/studium/exam_topics/biophysik +34 -0
  202. data/lib/studium/exam_topics/biopolymers +10 -0
  203. data/lib/studium/exam_topics/bioprozesstechnik +149 -0
  204. data/lib/studium/exam_topics/bioressourcenmanagement +78 -0
  205. data/lib/studium/exam_topics/birds +3 -0
  206. data/lib/studium/exam_topics/bodenkunde +373 -0
  207. data/lib/studium/exam_topics/bodenmikrobiologie +40 -0
  208. data/lib/studium/exam_topics/cancerbiology +454 -0
  209. data/lib/studium/exam_topics/cell_cultures +221 -0
  210. data/lib/studium/exam_topics/cellbiology +1011 -0
  211. data/lib/studium/exam_topics/cellular_transport_and_protein_secretion +27 -0
  212. data/lib/studium/exam_topics/cellular_vesicles +11 -0
  213. data/lib/studium/exam_topics/cellulose +6 -0
  214. data/lib/studium/exam_topics/chemische_technologie_anorganischer_stoffe +209 -0
  215. data/lib/studium/exam_topics/chemische_technologie_organischer_stoffe +25 -0
  216. data/lib/studium/exam_topics/chemisches_labor +60 -0
  217. data/lib/studium/exam_topics/chemotaxis_quorum_sensing_and_motility_in_prokaryotes +91 -0
  218. data/lib/studium/exam_topics/citric_acid_cycle +80 -0
  219. data/lib/studium/exam_topics/clinical_microbiology +506 -0
  220. data/lib/studium/exam_topics/computer_science +284 -0
  221. data/lib/studium/exam_topics/computer_vision_and_computer_graphics +12 -0
  222. data/lib/studium/exam_topics/crispr +48 -0
  223. data/lib/studium/exam_topics/cyanobacteria +43 -0
  224. data/lib/studium/exam_topics/cytogenetics_and_chromosome_biology +570 -0
  225. data/lib/studium/exam_topics/cytokines +6 -0
  226. data/lib/studium/exam_topics/databases_and_sql +116 -0
  227. data/lib/studium/exam_topics/dna_mutation_and_dna_repair +69 -0
  228. data/lib/studium/exam_topics/dna_replication +57 -0
  229. data/lib/studium/exam_topics/ecogenetics +26 -0
  230. data/lib/studium/exam_topics/ecological_agriculture +12 -0
  231. data/lib/studium/exam_topics/ecology +317 -0
  232. data/lib/studium/exam_topics/economy +211 -0
  233. data/lib/studium/exam_topics/elektronenmikroskopie +356 -0
  234. data/lib/studium/exam_topics/elektrophorese +89 -0
  235. data/lib/studium/exam_topics/elektrotechnik_und_elektrizit/303/244t +41 -0
  236. data/lib/studium/exam_topics/elisa +54 -0
  237. data/lib/studium/exam_topics/embryologie_und_entwicklung +603 -0
  238. data/lib/studium/exam_topics/endospores_and_spores +104 -0
  239. data/lib/studium/exam_topics/enzymes_and_cofactors +353 -0
  240. data/lib/studium/exam_topics/epigenetik +184 -0
  241. data/lib/studium/exam_topics/erste_hilfe +158 -0
  242. data/lib/studium/exam_topics/ethik +138 -0
  243. data/lib/studium/exam_topics/evolution_and_evolutionary_genetics +356 -0
  244. data/lib/studium/exam_topics/excel +7 -0
  245. data/lib/studium/exam_topics/fish +19 -0
  246. data/lib/studium/exam_topics/fluorescence_microscopy +7 -0
  247. data/lib/studium/exam_topics/food_microbiology_and_food_biotechnology +83 -0
  248. data/lib/studium/exam_topics/forensik +11 -0
  249. data/lib/studium/exam_topics/forstwirtschaft +53 -0
  250. data/lib/studium/exam_topics/fortgeschrittene_genetik +576 -0
  251. data/lib/studium/exam_topics/fortgeschrittene_gentechnik +217 -0
  252. data/lib/studium/exam_topics/fortgeschrittene_physik +6 -0
  253. data/lib/studium/exam_topics/fungi +80 -0
  254. data/lib/studium/exam_topics/genetische_krankheiten +187 -0
  255. data/lib/studium/exam_topics/genexpression +1008 -0
  256. data/lib/studium/exam_topics/genomics_and_metagenomics +272 -0
  257. data/lib/studium/exam_topics/gentechnik_und_praktische_biochemie +928 -0
  258. data/lib/studium/exam_topics/geochemistry +67 -0
  259. data/lib/studium/exam_topics/geography +8 -0
  260. data/lib/studium/exam_topics/geologie_und_mineralogie +626 -0
  261. data/lib/studium/exam_topics/geometrie +54 -0
  262. data/lib/studium/exam_topics/geschichte +94 -0
  263. data/lib/studium/exam_topics/gluconeogenesis +64 -0
  264. data/lib/studium/exam_topics/glycogen +25 -0
  265. data/lib/studium/exam_topics/glycolysis +109 -0
  266. data/lib/studium/exam_topics/glykomik +101 -0
  267. data/lib/studium/exam_topics/glyoxylatzyklus +31 -0
  268. data/lib/studium/exam_topics/grassland_cultivation +32 -0
  269. data/lib/studium/exam_topics/hormone +139 -0
  270. data/lib/studium/exam_topics/html +7 -0
  271. data/lib/studium/exam_topics/human_ecology +8 -0
  272. data/lib/studium/exam_topics/hygiene +224 -0
  273. data/lib/studium/exam_topics/imaging_and_microscopy +265 -0
  274. data/lib/studium/exam_topics/immunanalytik +94 -0
  275. data/lib/studium/exam_topics/immunologie +998 -0
  276. data/lib/studium/exam_topics/informatik +103 -0
  277. data/lib/studium/exam_topics/innate_immunity +24 -0
  278. data/lib/studium/exam_topics/insekten +64 -0
  279. data/lib/studium/exam_topics/insulin_and_diabetes +57 -0
  280. data/lib/studium/exam_topics/java +597 -0
  281. data/lib/studium/exam_topics/javascript +14 -0
  282. data/lib/studium/exam_topics/klima +6 -0
  283. data/lib/studium/exam_topics/kryptographie +9 -0
  284. data/lib/studium/exam_topics/landtechnik +26 -0
  285. data/lib/studium/exam_topics/lebensmittel +222 -0
  286. data/lib/studium/exam_topics/lebensmitteltechnologie +16 -0
  287. data/lib/studium/exam_topics/linux +5 -0
  288. data/lib/studium/exam_topics/lipids +95 -0
  289. data/lib/studium/exam_topics/macroeconomics +40 -0
  290. data/lib/studium/exam_topics/marketing +7 -0
  291. data/lib/studium/exam_topics/mathematics +280 -0
  292. data/lib/studium/exam_topics/medizin_und_biomedizinische_technik +251 -0
  293. data/lib/studium/exam_topics/medizinische_chemie_und_pharmazie +416 -0
  294. data/lib/studium/exam_topics/messtechnik_und_regeltechnik +104 -0
  295. data/lib/studium/exam_topics/metabolismus +423 -0
  296. data/lib/studium/exam_topics/meteorologie_und_atmosph/303/244re +91 -0
  297. data/lib/studium/exam_topics/microbial_ecology +35 -0
  298. data/lib/studium/exam_topics/microcontrollers +11 -0
  299. data/lib/studium/exam_topics/mikrobielle_lebensgemeinschaften +33 -0
  300. data/lib/studium/exam_topics/mikrobielle_physiologie +204 -0
  301. data/lib/studium/exam_topics/mitochondria +33 -0
  302. data/lib/studium/exam_topics/mixed +286 -0
  303. data/lib/studium/exam_topics/molecular_biology_of_plants +249 -0
  304. data/lib/studium/exam_topics/molekulare_medizin +133 -0
  305. data/lib/studium/exam_topics/nanotechnologie +453 -0
  306. data/lib/studium/exam_topics/nature_conservation_and_biodiversity +211 -0
  307. data/lib/studium/exam_topics/naturstoffe +9 -0
  308. data/lib/studium/exam_topics/netzwerke +34 -0
  309. data/lib/studium/exam_topics/neurobiology +272 -0
  310. data/lib/studium/exam_topics/nucleotide_sequencing +38 -0
  311. data/lib/studium/exam_topics/nutztierethologie +11 -0
  312. data/lib/studium/exam_topics/object_oriented_modeling +14 -0
  313. data/lib/studium/exam_topics/obstbau +249 -0
  314. data/lib/studium/exam_topics/organische_chemie +1007 -0
  315. data/lib/studium/exam_topics/organische_chemie_2 +125 -0
  316. data/lib/studium/exam_topics/paleobiology +39 -0
  317. data/lib/studium/exam_topics/parasitic_diseases_and_molecular_infection_biology +336 -0
  318. data/lib/studium/exam_topics/patent_law +55 -0
  319. data/lib/studium/exam_topics/pathologie +723 -0
  320. data/lib/studium/exam_topics/pcr +152 -0
  321. data/lib/studium/exam_topics/pentosephosphatweg +41 -0
  322. data/lib/studium/exam_topics/peroxisomes_glycosomes_and_lysosomes +66 -0
  323. data/lib/studium/exam_topics/pflanzenanatomie +255 -0
  324. data/lib/studium/exam_topics/pflanzenbau +24 -0
  325. data/lib/studium/exam_topics/pflanzenschutz +35 -0
  326. data/lib/studium/exam_topics/pflanzenwissenschaften +1009 -0
  327. data/lib/studium/exam_topics/pharmaceutical_biotechnology +251 -0
  328. data/lib/studium/exam_topics/physik +443 -1
  329. data/lib/studium/exam_topics/physikalische_chemie +86 -0
  330. data/lib/studium/exam_topics/physiology_and_histology +520 -0
  331. data/lib/studium/exam_topics/phytochemie +33 -0
  332. data/lib/studium/exam_topics/plant_biotechnology +129 -0
  333. data/lib/studium/exam_topics/plant_breeding +64 -0
  334. data/lib/studium/exam_topics/plant_development +50 -0
  335. data/lib/studium/exam_topics/populationsgenetik +137 -0
  336. data/lib/studium/exam_topics/posttranslationale_modifikation_von_proteinen +195 -0
  337. data/lib/studium/exam_topics/projektmanagement +220 -0
  338. data/lib/studium/exam_topics/prokaryote_genetics +547 -0
  339. data/lib/studium/exam_topics/protein_engineering +16 -0
  340. data/lib/studium/exam_topics/proteolyse +36 -0
  341. data/lib/studium/exam_topics/proteomik +40 -0
  342. data/lib/studium/exam_topics/prozesstechnik +95 -0
  343. data/lib/studium/exam_topics/psychologie +14 -0
  344. data/lib/studium/exam_topics/python +355 -0
  345. data/lib/studium/exam_topics/quality_management +263 -0
  346. data/lib/studium/exam_topics/rechtsgrundlagen +116 -0
  347. data/lib/studium/exam_topics/research_topics_in_immunobiology +42 -0
  348. data/lib/studium/exam_topics/rna_and_dna +457 -0
  349. data/lib/studium/exam_topics/rna_seq +11 -0
  350. data/lib/studium/exam_topics/robotik +6 -0
  351. data/lib/studium/exam_topics/ruby +183 -0
  352. data/lib/studium/exam_topics/ruby_on_rails +63 -0
  353. data/lib/studium/exam_topics/scientific_writing_and_publishing +38 -0
  354. data/lib/studium/exam_topics/semisynthese_von_proteinen_und_nukleotiden +120 -0
  355. data/lib/studium/exam_topics/sexualbiologie +108 -0
  356. data/lib/studium/exam_topics/signal_transduction_and_laser_systems +197 -0
  357. data/lib/studium/exam_topics/splicing_exons_and_introns +63 -0
  358. data/lib/studium/exam_topics/statistik +241 -0
  359. data/lib/studium/exam_topics/stemcells +159 -0
  360. data/lib/studium/exam_topics/stickstofffixierung +76 -0
  361. data/lib/studium/exam_topics/structural_bioinformatics +54 -0
  362. data/lib/studium/exam_topics/strukturbiologie +387 -0
  363. data/lib/studium/exam_topics/system_biology_and_synthetic_biology +103 -0
  364. data/lib/studium/exam_topics/systematische_zoologie +436 -0
  365. data/lib/studium/exam_topics/technical_ecology +144 -0
  366. data/lib/studium/exam_topics/technische_chemie +204 -0
  367. data/lib/studium/exam_topics/technische_grundlagen_der_informatik +39 -0
  368. data/lib/studium/exam_topics/technische_mikrobiologie +393 -0
  369. data/lib/studium/exam_topics/technisches_zeichnen +5 -0
  370. data/lib/studium/exam_topics/the_bacterial_cell_wall +97 -0
  371. data/lib/studium/exam_topics/the_c_plus_plus_programming_language +491 -0
  372. data/lib/studium/exam_topics/the_c_programming_language +129 -0
  373. data/lib/studium/exam_topics/the_cellcycle +89 -0
  374. data/lib/studium/exam_topics/the_european_union +119 -0
  375. data/lib/studium/exam_topics/the_interferon_system +39 -0
  376. data/lib/studium/exam_topics/the_microbiome +164 -0
  377. data/lib/studium/exam_topics/the_universe +26 -0
  378. data/lib/studium/exam_topics/theoretische_chemie +5 -0
  379. data/lib/studium/exam_topics/theoretische_informatik +157 -0
  380. data/lib/studium/exam_topics/thermodynamics +3 -0
  381. data/lib/studium/exam_topics/tierzucht +139 -0
  382. data/lib/studium/exam_topics/toxikologie +447 -0
  383. data/lib/studium/exam_topics/transcription +164 -0
  384. data/lib/studium/exam_topics/translation_ribosomes_and_translational_control +144 -0
  385. data/lib/studium/exam_topics/umweltbiotechnologie +64 -0
  386. data/lib/studium/exam_topics/umweltchemie +233 -0
  387. data/lib/studium/exam_topics/urbanism_and_traffic +19 -0
  388. data/lib/studium/exam_topics/urea_cycle +55 -0
  389. data/lib/studium/exam_topics/vaccines_and_vaccination +246 -0
  390. data/lib/studium/exam_topics/vectors_and_gene_therapy +246 -0
  391. data/lib/studium/exam_topics/verfahrenstechnik +37 -0
  392. data/lib/studium/exam_topics/veterinary_medicine +10 -0
  393. data/lib/studium/exam_topics/vitamine +25 -0
  394. data/lib/studium/exam_topics/wasserkunde +137 -0
  395. data/lib/studium/exam_topics/weinbau +82 -0
  396. data/lib/studium/exam_topics/wissenschaft +18 -0
  397. data/lib/studium/exam_topics/yeast +102 -0
  398. data/lib/studium/exam_topics/zoologie +333 -0
  399. data/lib/studium/exams/afterburn/afterburn.rb +257 -0
  400. data/lib/studium/exams/ask_exam_from_the_upcoming_exams_pool.rb +150 -0
  401. data/lib/studium/exams/ask_exam_topic_question.rb +112 -0
  402. data/lib/studium/exams/ask_question_from_alias.rb +141 -0
  403. data/lib/studium/exams/ask_question_from_any_of_the_still_missing_lectures.rb +131 -0
  404. data/lib/studium/exams/ask_question_from_grouped_themes.rb +141 -0
  405. data/lib/studium/exams/ask_question_from_last_topic.rb +91 -0
  406. data/lib/studium/exams/ask_random_question.rb +195 -0
  407. data/lib/studium/exams/autoinclude.rb +7 -0
  408. data/lib/studium/exams/average_grade.rb +396 -0
  409. data/lib/studium/exams/csv/create_csv_passed_exams_file.rb +217 -0
  410. data/lib/studium/exams/cycle.rb +291 -0
  411. data/lib/studium/exams/dataset.rb +124 -0
  412. data/lib/studium/exams/designate_ten_random_exam_topics/designate_ten_random_exam_topics.rb +88 -0
  413. data/lib/studium/exams/exam/exam.rb +130 -0
  414. data/lib/studium/exams/exam_question/README.md +3 -0
  415. data/lib/studium/exams/exam_question/answer.rb +193 -0
  416. data/lib/studium/exams/exam_question/constants.rb +111 -0
  417. data/lib/studium/exams/exam_question/exam_question.rb +1136 -0
  418. data/lib/studium/exams/exam_question/menu.rb +333 -0
  419. data/lib/studium/exams/exam_question/misc.rb +898 -0
  420. data/lib/studium/exams/exam_question/question.rb +91 -0
  421. data/lib/studium/exams/exam_question/reset.rb +96 -0
  422. data/lib/studium/exams/exam_registration_at/constants.rb +49 -0
  423. data/lib/studium/exams/exam_registration_at/exam_registration_at.rb +242 -0
  424. data/lib/studium/exams/exam_registration_at/help.rb +46 -0
  425. data/lib/studium/exams/exam_registration_at/menu.rb +81 -0
  426. data/lib/studium/exams/exam_registration_at/report_and_show.rb +133 -0
  427. data/lib/studium/exams/exam_registration_at/reset.rb +54 -0
  428. data/lib/studium/exams/exam_statistics_from_this_file/exam_statistics_from_this_file.rb +119 -0
  429. data/lib/studium/exams/exam_topics.rb +194 -0
  430. data/lib/studium/exams/exams.rb +20 -0
  431. data/lib/studium/exams/exams_per_month/exams_per_month.rb +2438 -0
  432. data/lib/studium/exams/exams_this_week.rb +182 -0
  433. data/lib/studium/exams/fix_exam_dates.rb +121 -0
  434. data/lib/studium/exams/frozen.rb +36 -0
  435. data/lib/studium/exams/last_exams/last_exams.rb +398 -0
  436. data/lib/studium/exams/lectures_without_exam_entry.rb +137 -0
  437. data/lib/studium/exams/mandatory_continuous_assessment/mandatory_continuous_assessment.rb +1359 -0
  438. data/lib/studium/exams/move_the_last_exam_question_to_the_top_of_the_file/move_the_last_exam_question_to_the_top_of_the_file.rb +111 -0
  439. data/lib/studium/exams/n_exams_in_these_topics.rb +404 -0
  440. data/lib/studium/exams/next_exam.rb +107 -0
  441. data/lib/studium/exams/next_exams.rb +378 -0
  442. data/lib/studium/exams/open_exam_associated_url.rb +154 -0
  443. data/lib/studium/exams/open_last_exam_question_asked_file/constants.rb +15 -0
  444. data/lib/studium/exams/open_last_exam_question_asked_file/initialize.rb +29 -0
  445. data/lib/studium/exams/open_last_exam_question_asked_file/open_last_exam_question_asked_file.rb +109 -0
  446. data/lib/studium/exams/push_solved_questions_on_top.rb +180 -0
  447. data/lib/studium/exams/questions_solved_from_day_to_day/questions_solved_from_day_to_day.rb +377 -0
  448. data/lib/studium/exams/remote_ftp_url.rb +52 -0
  449. data/lib/studium/exams/repeat_last_question.rb +78 -0
  450. data/lib/studium/exams/show_all_passed_exams_of_this_university.rb +252 -0
  451. data/lib/studium/exams/show_backlog_of_exams.rb +117 -0
  452. data/lib/studium/exams/show_next_exams_for.rb +133 -0
  453. data/lib/studium/exams/show_themes/constants.rb +28 -0
  454. data/lib/studium/exams/show_themes/menu.rb +61 -0
  455. data/lib/studium/exams/show_themes/misc.rb +537 -0
  456. data/lib/studium/exams/show_themes/reset.rb +62 -0
  457. data/lib/studium/exams/show_themes/show_themes.rb +27 -0
  458. data/lib/studium/exams/show_upcoming_exams/show_upcoming_exams.rb +1146 -0
  459. data/lib/studium/exams/solve_all_questions_from_this_topic.rb +114 -0
  460. data/lib/studium/exams/solved/constants.rb +32 -0
  461. data/lib/studium/exams/solved/help.rb +24 -0
  462. data/lib/studium/exams/solved/initialize.rb +55 -0
  463. data/lib/studium/exams/solved/menu.rb +41 -0
  464. data/lib/studium/exams/solved/reset.rb +28 -0
  465. data/lib/studium/exams/solved/solved.rb +317 -0
  466. data/lib/studium/exams/timetable/timetable.rb +510 -0
  467. data/lib/studium/exams/unsolve_all_questions_from_this_topic.rb +162 -0
  468. data/lib/studium/exams/upcoming_exams/upcoming_exams.rb +556 -0
  469. data/lib/studium/exams/upcoming_exams_at_the_boku/constants.rb +23 -0
  470. data/lib/studium/exams/upcoming_exams_at_the_boku/html.rb +64 -0
  471. data/lib/studium/exams/upcoming_exams_at_the_boku/upcoming_exams_at_the_boku.rb +194 -0
  472. data/lib/studium/exams/upcoming_exams_dataset.rb +247 -0
  473. data/lib/studium/exams/upcoming_registered_exams/upcoming_registered_exams.rb +257 -0
  474. data/lib/studium/exams/upload_exam_topics.rb +360 -0
  475. data/lib/studium/graphviz/README.md +4 -0
  476. data/lib/studium/graphviz/bachelor_vector_based_strategies.dot +160 -0
  477. data/lib/studium/graphviz/master_vector_based_strategies.dot +46 -0
  478. data/lib/studium/gui/gtk3/README.md +1 -0
  479. data/lib/studium/gui/gtk3/ask_exam_question/ask_exam_question.config +6 -0
  480. data/lib/studium/gui/gtk3/ask_exam_question/ask_exam_question.rb +760 -0
  481. data/lib/studium/gui/gtk3/ask_exam_question/manifest.yml +12 -0
  482. data/lib/studium/gui/gtk3/control_panel/control_panel.rb +39 -0
  483. data/lib/studium/gui/gtk3/curriculum_viewer/curriculum_viewer.rb +510 -0
  484. data/lib/studium/gui/gtk3/ects_per_university/ects_per_university.rb +217 -0
  485. data/lib/studium/gui/gtk3/exam_question_widget/exam_question_widget.rb +1888 -0
  486. data/lib/studium/gui/gtk3/expand_time_range/expand_time_range.rb +34 -0
  487. data/lib/studium/gui/gtk3/information_about_a_lecture/information_about_a_lecture.rb +34 -0
  488. data/lib/studium/gui/gtk3/lecture_information/lecture_information.rb +200 -0
  489. data/lib/studium/gui/gtk3/show_upcoming_exams/show_upcoming_exams.rb +34 -0
  490. data/lib/studium/gui/java/exam_question/ExamQuestion$1.class +0 -0
  491. data/lib/studium/gui/java/exam_question/ExamQuestion.class +0 -0
  492. data/lib/studium/gui/java/exam_question/ExamQuestion.java +215 -0
  493. data/lib/studium/gui/javafx/exam_question_widget/exam_question_widget.rb +58 -0
  494. data/lib/studium/gui/jruby/exam_question_widget/exam_question_widget.rb +317 -0
  495. data/lib/studium/gui/libui/ask_exam_question/ask_exam_question.rb +349 -0
  496. data/lib/studium/gui/shared_code/control_panel/control_panel_module.rb +314 -0
  497. data/lib/studium/gui/shared_code/exam_question_widget/exam_question_widget_module.rb +39 -0
  498. data/lib/studium/gui/shared_code/expand_time_range/expand_time_range.css +0 -0
  499. data/lib/studium/gui/shared_code/expand_time_range/expand_time_range_module.rb +190 -0
  500. data/lib/studium/gui/shared_code/information_about_a_lecture/information_about_a_lecture_module.rb +180 -0
  501. data/lib/studium/gui/shared_code/show_upcoming_exams/show_upcoming_exams_module.rb +206 -0
  502. data/lib/studium/images/libui_ask_exam_question.png +0 -0
  503. data/lib/studium/images/outdated.png +0 -0
  504. data/lib/studium/images/small_logos/DNA.png +0 -0
  505. data/lib/studium/images/small_logos/README.md +2 -0
  506. data/lib/studium/images/small_logos/solved.png +0 -0
  507. data/lib/studium/images/studies_favicon.png +0 -0
  508. data/lib/studium/java/Mkdir.java +15 -0
  509. data/lib/studium/java/README.md +2 -0
  510. data/lib/studium/java/ask_exam_question/AskExamQuestion.class +0 -0
  511. data/lib/studium/java/ask_exam_question/AskExamQuestion.java +480 -0
  512. data/lib/studium/java/constants/Constants.class +0 -0
  513. data/lib/studium/java/constants/Constants.java +77 -0
  514. data/lib/studium/java/solved/Solved.class +0 -0
  515. data/lib/studium/java/solved/Solved.java +110 -0
  516. data/lib/studium/java/utility_scripts/OpenLastExamQuestionurlLinkViaTheBrowser.class +0 -0
  517. data/lib/studium/java/utility_scripts/OpenLastExamQuestionurlLinkViaTheBrowser.java +80 -0
  518. data/lib/studium/logging/README.md +2 -0
  519. data/lib/studium/logging/ensure_that_the_log_directory_exists.rb +47 -0
  520. data/lib/studium/logging/html_log_directory.rb +41 -0
  521. data/lib/studium/logging/log_directory.rb +112 -0
  522. data/lib/studium/logging/store_last_question_asked_into_file.rb +137 -0
  523. data/lib/studium/parsers/README.md +2 -0
  524. data/lib/studium/parsers/custom_exam_results_parser.rb +206 -0
  525. data/lib/studium/parsers/parse_lva_dates.rb +233 -0
  526. data/lib/studium/parsers/parse_remote_lecture.rb +331 -0
  527. data/lib/studium/project/project.rb +76 -0
  528. data/lib/studium/requires/common_popular_requires.rb +37 -0
  529. data/lib/studium/requires/commonly_used_requires.rb +14 -0
  530. data/lib/studium/requires/require_class_exams_solved.rb +7 -0
  531. data/lib/studium/requires/require_ects_scripts.rb +27 -0
  532. data/lib/studium/requires/require_encoding.rb +7 -0
  533. data/lib/studium/requires/require_the_check_and_sanitize_files.rb +31 -0
  534. data/lib/studium/requires/require_the_curricula_files.rb +28 -0
  535. data/lib/studium/requires/require_the_exam_question_class.rb +7 -0
  536. data/lib/studium/requires/require_the_exams_files.rb +45 -0
  537. data/lib/studium/requires/require_the_logging_files.rb +23 -0
  538. data/lib/studium/requires/require_the_parsers.rb +28 -0
  539. data/lib/studium/requires/require_the_studium_constants.rb +10 -0
  540. data/lib/studium/requires/require_the_studium_project.rb +60 -0
  541. data/lib/studium/requires/require_the_toplevel_methods.rb +27 -0
  542. data/lib/studium/requires/require_the_utility_scripts.rb +49 -0
  543. data/lib/studium/requires/require_upcoming_exams.rb +7 -0
  544. data/lib/studium/requires/require_yaml.rb +7 -0
  545. data/lib/studium/requires/return_remote_homepage_of_this_lecture.rb +7 -0
  546. data/lib/studium/requires/with_GUI.rb +13 -0
  547. data/lib/studium/requires/www_mode.rb +17 -0
  548. data/lib/studium/statistics/README.md +4 -0
  549. data/lib/studium/statistics/best_exam_months.rb +92 -0
  550. data/lib/studium/statistics/curriculum_comparer.rb +337 -0
  551. data/lib/studium/statistics/determine_exam_statistics_from_this_file.rb +142 -0
  552. data/lib/studium/statistics/exam_topics_that_are_about_to_be_completed.rb +119 -0
  553. data/lib/studium/statistics/max_stats.rb +170 -0
  554. data/lib/studium/statistics/new_questions_per_year.rb +147 -0
  555. data/lib/studium/statistics/report_how_many_ects_points_per_curriculum_were_completed.rb +167 -0
  556. data/lib/studium/statistics/report_how_many_exam_questions_were_answered.rb +473 -0
  557. data/lib/studium/statistics/show_exam_statistics.rb +66 -0
  558. data/lib/studium/statistics/show_which_courses_are_in_a_bachelor_or_master_curriculum_respectively.rb +104 -0
  559. data/lib/studium/statistics/top_stats.rb +127 -0
  560. data/lib/studium/toplevel_methods/all_passed_exams.rb +37 -0
  561. data/lib/studium/toplevel_methods/already_solved_this_lecture.rb +100 -0
  562. data/lib/studium/toplevel_methods/available_topics.rb +156 -0
  563. data/lib/studium/toplevel_methods/calculate_pr/303/274fungsimmanente_lectures_from_this_file.rb +55 -0
  564. data/lib/studium/toplevel_methods/copy_the_last_backup_of_file_lecture_information.rb +34 -0
  565. data/lib/studium/toplevel_methods/curriculum_related_code.rb +1082 -0
  566. data/lib/studium/toplevel_methods/determine_local_directory_of_this_lecture.rb +72 -0
  567. data/lib/studium/toplevel_methods/does_this_course_require_mandatory_presence.rb +51 -0
  568. data/lib/studium/toplevel_methods/download.rb +163 -0
  569. data/lib/studium/toplevel_methods/e.rb +16 -0
  570. data/lib/studium/toplevel_methods/ects_from_lectures.rb +250 -0
  571. data/lib/studium/toplevel_methods/editor.rb +65 -0
  572. data/lib/studium/toplevel_methods/esystem.rb +22 -0
  573. data/lib/studium/toplevel_methods/filter_away_invalid_questions.rb +77 -0
  574. data/lib/studium/toplevel_methods/find_exam_topic_and_exam_title.rb +3538 -0
  575. data/lib/studium/toplevel_methods/handle_archive_of_the_exam_questions.rb +136 -0
  576. data/lib/studium/toplevel_methods/has_this_lecture_been_already_passed_but_the_id_was_changed_lateron.rb +42 -0
  577. data/lib/studium/toplevel_methods/has_this_module_been_completed.rb +206 -0
  578. data/lib/studium/toplevel_methods/install_the_project_on_the_given_hostsystem.rb +32 -0
  579. data/lib/studium/toplevel_methods/is_on_roebe.rb +26 -0
  580. data/lib/studium/toplevel_methods/is_this_exam_topic_included.rb +46 -0
  581. data/lib/studium/toplevel_methods/is_this_homepage_registered.rb +31 -0
  582. data/lib/studium/toplevel_methods/is_this_lecture_a_practical_course.rb +93 -0
  583. data/lib/studium/toplevel_methods/is_this_lecture_registered_in_upcoming_exams.rb +42 -0
  584. data/lib/studium/toplevel_methods/java.rb +32 -0
  585. data/lib/studium/toplevel_methods/lecture_information.rb +108 -0
  586. data/lib/studium/toplevel_methods/lva_numbers.rb +355 -0
  587. data/lib/studium/toplevel_methods/main_dataset.rb +73 -0
  588. data/lib/studium/toplevel_methods/map_input_to_this_curriculum_filename.rb +595 -0
  589. data/lib/studium/toplevel_methods/methods_related_to_directories.rb +225 -0
  590. data/lib/studium/toplevel_methods/methods_related_to_files.rb +209 -0
  591. data/lib/studium/toplevel_methods/misc.rb +288 -0
  592. data/lib/studium/toplevel_methods/n_questions_available.rb +137 -0
  593. data/lib/studium/toplevel_methods/n_topics_available.rb +63 -0
  594. data/lib/studium/toplevel_methods/names_of_all_solved_exams.rb +71 -0
  595. data/lib/studium/toplevel_methods/note_down_the_start_time_and_how_many_exams_have_been_already_solved.rb +69 -0
  596. data/lib/studium/toplevel_methods/opnn.rb +25 -0
  597. data/lib/studium/toplevel_methods/passed_this_exam_on.rb +105 -0
  598. data/lib/studium/toplevel_methods/pristine.rb +69 -0
  599. data/lib/studium/toplevel_methods/read_delay_between_questions_from_file.rb +34 -0
  600. data/lib/studium/toplevel_methods/regexes.rb +90 -0
  601. data/lib/studium/toplevel_methods/registered_for_this_exam.rb +82 -0
  602. data/lib/studium/toplevel_methods/remove_comments.rb +26 -0
  603. data/lib/studium/toplevel_methods/remove_exam_topics_that_were_already_answered.rb +27 -0
  604. data/lib/studium/toplevel_methods/remove_tags.rb +32 -0
  605. data/lib/studium/toplevel_methods/report.rb +435 -0
  606. data/lib/studium/toplevel_methods/return_all_exams_on_this_day.rb +66 -0
  607. data/lib/studium/toplevel_methods/return_dataset_for_this_exam_topic.rb +41 -0
  608. data/lib/studium/toplevel_methods/return_ects_from_this_lecture_stored_in_the_file_lecture_information.rb +194 -0
  609. data/lib/studium/toplevel_methods/return_hash_of_already_solved_lectures.rb +46 -0
  610. data/lib/studium/toplevel_methods/return_last_exam_question.rb +34 -0
  611. data/lib/studium/toplevel_methods/return_local_path_of_this_pwdstud.rb +60 -0
  612. data/lib/studium/toplevel_methods/return_lva_number_of_this_lecture.rb +72 -0
  613. data/lib/studium/toplevel_methods/return_n_percent_solved_from_this_topic.rb +90 -0
  614. data/lib/studium/toplevel_methods/return_n_questions_were_answered_for_this_topic.rb +60 -0
  615. data/lib/studium/toplevel_methods/return_proper_university_image.rb +86 -0
  616. data/lib/studium/toplevel_methods/return_question_answer_string_from_this_topic.rb +63 -0
  617. data/lib/studium/toplevel_methods/return_remote_homepage_of_this_lecture.rb +10951 -0
  618. data/lib/studium/toplevel_methods/return_remote_moodle_link_of_this_lecture.rb +2201 -0
  619. data/lib/studium/toplevel_methods/return_sanitized_dataset_from_the_file_lecture_information.rb +110 -0
  620. data/lib/studium/toplevel_methods/return_theme_of_the_next_upcoming_exam.rb +38 -0
  621. data/lib/studium/toplevel_methods/rinstall2.rb +34 -0
  622. data/lib/studium/toplevel_methods/rti_conflict.rb +35 -0
  623. data/lib/studium/toplevel_methods/runmode.rb +87 -0
  624. data/lib/studium/toplevel_methods/sanitized_dataset_from_file_passed_exams_per_month.rb +52 -0
  625. data/lib/studium/toplevel_methods/set_last_file_for_exam_questions.rb +64 -0
  626. data/lib/studium/toplevel_methods/set_this_cd_alias_to.rb +86 -0
  627. data/lib/studium/toplevel_methods/show_passed_exams_having_this_grade.rb +34 -0
  628. data/lib/studium/toplevel_methods/spacer.rb +18 -0
  629. data/lib/studium/toplevel_methods/time.rb +297 -0
  630. data/lib/studium/toplevel_methods/total_ects_points_passed.rb +72 -0
  631. data/lib/studium/toplevel_methods/try_to_guess_the_most_likely_lva_id.rb +57 -0
  632. data/lib/studium/toplevel_methods/try_to_return_the_expanded_name_of_this_lecture.rb +63 -0
  633. data/lib/studium/toplevel_methods/unfinished.rb +51 -0
  634. data/lib/studium/toplevel_methods/url.rb +100 -0
  635. data/lib/studium/toplevel_methods/verbose_truth.rb +36 -0
  636. data/lib/studium/toplevel_methods/when_was_this_lecture_passed.rb +54 -0
  637. data/lib/studium/toplevel_methods/word_wrap.rb +56 -0
  638. data/lib/studium/toplevel_methods/write_into_file_related_functionality.rb +195 -0
  639. data/lib/studium/toplevel_methods/yes_or_no_ja_oder_nein.rb +33 -0
  640. data/lib/studium/universities_in_austria/README.md +2 -0
  641. data/lib/studium/universities_in_austria/boku/README.md +4 -0
  642. data/lib/studium/universities_in_austria/boku/boku_/303/266ffnungszeiten.rb +28 -0
  643. data/lib/studium/universities_in_austria/boku/show_three_pillars_of_these_lectures.rb +110 -0
  644. data/lib/studium/universities_in_austria/boku/three_pillars.rb +237 -0
  645. data/lib/studium/universities_in_austria/tu_vienna/README.md +6 -0
  646. data/lib/studium/universities_in_austria/tu_vienna/tu_ferien.rb +42 -0
  647. data/lib/studium/universities_in_austria/tu_vienna/tu_/303/266ffnungszeiten.rb +34 -0
  648. data/lib/studium/university_course/university_course.rb +384 -0
  649. data/lib/studium/utility_scripts/attribute_lecture_to_curriculum/attribute_boku_lecture_to_curriculum.rb +384 -0
  650. data/lib/studium/utility_scripts/attribute_lecture_to_curriculum/attribute_lecture_to_curriculum.rb +238 -0
  651. data/lib/studium/utility_scripts/attribute_lectures_to_university/attribute_lectures_to_university.rb +375 -0
  652. data/lib/studium/utility_scripts/audio_stats.rb +171 -0
  653. data/lib/studium/utility_scripts/auto_stud/auto_stud.rb +252 -0
  654. data/lib/studium/utility_scripts/auto_stud/constants.rb +18 -0
  655. data/lib/studium/utility_scripts/auto_stud/initialize.rb +23 -0
  656. data/lib/studium/utility_scripts/auto_stud/misc.rb +18 -0
  657. data/lib/studium/utility_scripts/autopurge_this_lecture_date.rb +93 -0
  658. data/lib/studium/utility_scripts/average_grade_of_this_curriculum.rb +143 -0
  659. data/lib/studium/utility_scripts/blocked_courses.rb +141 -0
  660. data/lib/studium/utility_scripts/calendar/README.md +2 -0
  661. data/lib/studium/utility_scripts/calendar/calendar.rb +251 -0
  662. data/lib/studium/utility_scripts/calendar/misc.rb +35 -0
  663. data/lib/studium/utility_scripts/check_description_of_these_lectures.rb +221 -0
  664. data/lib/studium/utility_scripts/course_registrations/course_registrations.rb +98 -0
  665. data/lib/studium/utility_scripts/create/README.md +2 -0
  666. data/lib/studium/utility_scripts/create/webpage_of_university.rb +129 -0
  667. data/lib/studium/utility_scripts/create/webpage_of_university_BOKU.rb +59 -0
  668. data/lib/studium/utility_scripts/create/webpage_of_university_TU.rb +58 -0
  669. data/lib/studium/utility_scripts/create/webpage_of_university_UniWien.rb +57 -0
  670. data/lib/studium/utility_scripts/create_database/create_database.rb +106 -0
  671. data/lib/studium/utility_scripts/current_lectures_belonging_to_both_bachelor_and_master_curriculum.rb +113 -0
  672. data/lib/studium/utility_scripts/currently_participating_in_these_lectures/currently_participating_in_these_lectures.rb +104 -0
  673. data/lib/studium/utility_scripts/display_lecture_url.rb +176 -0
  674. data/lib/studium/utility_scripts/expand_time_range/expand_time_range.rb +488 -0
  675. data/lib/studium/utility_scripts/finished_exams_at_this_university.rb +94 -0
  676. data/lib/studium/utility_scripts/foreign_language_percentage/constants.rb +23 -0
  677. data/lib/studium/utility_scripts/foreign_language_percentage/foreign_language_percentage.rb +149 -0
  678. data/lib/studium/utility_scripts/foreign_language_percentage/help.rb +31 -0
  679. data/lib/studium/utility_scripts/foreign_language_percentage/initialize.rb +25 -0
  680. data/lib/studium/utility_scripts/foreign_language_percentage/menu.rb +158 -0
  681. data/lib/studium/utility_scripts/foreign_language_percentage/report.rb +62 -0
  682. data/lib/studium/utility_scripts/foreign_language_percentage/reset.rb +50 -0
  683. data/lib/studium/utility_scripts/foreign_language_percentage/run.rb +19 -0
  684. data/lib/studium/utility_scripts/generate_spreadsheet/generate_spreadsheet.rb +354 -0
  685. data/lib/studium/utility_scripts/generate_spreadsheet/misc.rb +144 -0
  686. data/lib/studium/utility_scripts/holidays/holidays.rb +150 -0
  687. data/lib/studium/utility_scripts/homepage_of_these_courses.rb +118 -0
  688. data/lib/studium/utility_scripts/lecture_downloader.rb +107 -0
  689. data/lib/studium/utility_scripts/lectures_attributed_to_universities.rb +336 -0
  690. data/lib/studium/utility_scripts/lva_dates_of_the_important_courses.rb +111 -0
  691. data/lib/studium/utility_scripts/lva_nummer.rb +431 -0
  692. data/lib/studium/utility_scripts/mandatory_lectures_in_this_month/mandatory_lectures_in_this_month.rb +316 -0
  693. data/lib/studium/utility_scripts/name_of_this_lva_id.rb +110 -0
  694. data/lib/studium/utility_scripts/new_stud.rb +324 -0
  695. data/lib/studium/utility_scripts/next_week.rb +103 -0
  696. data/lib/studium/utility_scripts/open_last_exam_question_url_link_via_the_browser.rb +76 -0
  697. data/lib/studium/utility_scripts/passed_ects_per_year/passed_ects_per_year.rb +288 -0
  698. data/lib/studium/utility_scripts/passed_pr/303/274fungsimmanente_courses/passed_pr/303/274fungsimmanente_courses.rb +181 -0
  699. data/lib/studium/utility_scripts/pdf/README.md +2 -0
  700. data/lib/studium/utility_scripts/pdf/create_pdf_file_for_this_exam_topic.rb +355 -0
  701. data/lib/studium/utility_scripts/pdf/hexapdf_support.rb +50 -0
  702. data/lib/studium/utility_scripts/preparatory_meetings/preparatory_meetings.rb +312 -0
  703. data/lib/studium/utility_scripts/priority.rb +164 -0
  704. data/lib/studium/utility_scripts/priority_points/priority_points.rb +263 -0
  705. data/lib/studium/utility_scripts/publish_my_exams.rb +174 -0
  706. data/lib/studium/utility_scripts/regexes/README.md +1 -0
  707. data/lib/studium/utility_scripts/regexes/generate_regex.rb +314 -0
  708. data/lib/studium/utility_scripts/regexes/generate_regexes_for_the_available_moodle_links.rb +55 -0
  709. data/lib/studium/utility_scripts/regexes/generate_regexes_for_the_registered_lectures.rb +48 -0
  710. data/lib/studium/utility_scripts/report_outdated_timetable_entries/report_outdated_timetable_entries.rb +142 -0
  711. data/lib/studium/utility_scripts/report_total_amount_of_questions_and_answers_for.rb +116 -0
  712. data/lib/studium/utility_scripts/report_whether_this_lecture_is_registered_in_the_file_lecture_information.rb +128 -0
  713. data/lib/studium/utility_scripts/resolve_practical_courses_date_conflicts/individual_resolve_practical_courses_date_conflicts.rb +254 -0
  714. data/lib/studium/utility_scripts/resolve_practical_courses_date_conflicts/resolve_practical_courses_date_conflicts.rb +265 -0
  715. data/lib/studium/utility_scripts/scrape_remote_university_url.rb +138 -0
  716. data/lib/studium/utility_scripts/semester_schedule_creator/semester_container.rb +144 -0
  717. data/lib/studium/utility_scripts/semester_schedule_creator/semester_schedule_creator.rb +374 -0
  718. data/lib/studium/utility_scripts/semesterplaner.rb +289 -0
  719. data/lib/studium/utility_scripts/set_aliases_based_on_this_file.rb +97 -0
  720. data/lib/studium/utility_scripts/show_all_passed_master_lectures.rb +119 -0
  721. data/lib/studium/utility_scripts/show_conflicting_lva_lectures/show_conflicting_lva_lectures.rb +1339 -0
  722. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/constants.rb +23 -0
  723. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/menu.rb +63 -0
  724. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/reset.rb +33 -0
  725. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/run.rb +50 -0
  726. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/show_descriptions_of_lectures_belonging_to_this_module.rb +145 -0
  727. data/lib/studium/utility_scripts/show_lecturers/show_lecturers.rb +147 -0
  728. data/lib/studium/utility_scripts/show_lectures/constants.rb +11 -0
  729. data/lib/studium/utility_scripts/show_lectures/help.rb +35 -0
  730. data/lib/studium/utility_scripts/show_lectures/initialize.rb +23 -0
  731. data/lib/studium/utility_scripts/show_lectures/menu.rb +138 -0
  732. data/lib/studium/utility_scripts/show_lectures/misc.rb +606 -0
  733. data/lib/studium/utility_scripts/show_lectures/reset.rb +89 -0
  734. data/lib/studium/utility_scripts/show_lectures/run.rb +28 -0
  735. data/lib/studium/utility_scripts/show_lectures/show_lectures.rb +49 -0
  736. data/lib/studium/utility_scripts/show_lectures_fitting_to_this_language/show_lectures_fitting_to_this_language.rb +121 -0
  737. data/lib/studium/utility_scripts/show_lectures_fitting_to_this_theme/show_lectures_fitting_to_this_theme.rb +105 -0
  738. data/lib/studium/utility_scripts/show_lectures_on_the_commandline/show_lectures_on_the_commandline.rb +3142 -0
  739. data/lib/studium/utility_scripts/show_lectures_on_this_day.rb +149 -0
  740. data/lib/studium/utility_scripts/show_lva_dates_of_this_lecture.rb +169 -0
  741. data/lib/studium/utility_scripts/show_mixed_bachelor_master_courses/show_mixed_bachelor_master_courses.rb +91 -0
  742. data/lib/studium/utility_scripts/show_outdated_lva_dates/show_outdated_lva_dates.rb +210 -0
  743. data/lib/studium/utility_scripts/show_solved_english_lectures/show_solved_english_lectures.rb +139 -0
  744. data/lib/studium/utility_scripts/steop/README.md +4 -0
  745. data/lib/studium/utility_scripts/steop/show_all_steop_lectures.rb +93 -0
  746. data/lib/studium/utility_scripts/steop/steop_lectures_in_this_curriculum.rb +284 -0
  747. data/lib/studium/utility_scripts/steop/steop_lva_dates.rb +119 -0
  748. data/lib/studium/utility_scripts/studienkennzahl.rb +116 -0
  749. data/lib/studium/utility_scripts/studium_skeleton/studium_skeleton.rb +231 -0
  750. data/lib/studium/utility_scripts/stundenplan.rb +595 -0
  751. data/lib/studium/utility_scripts/sync_studium_relevant_entries_one_level_downwards.rb +217 -0
  752. data/lib/studium/utility_scripts/ufind/ufind.rb +98 -0
  753. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/constants.rb +26 -0
  754. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/run.rb +20 -0
  755. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/upcoming_mandatory_presence_courses.rb +187 -0
  756. data/lib/studium/utility_scripts/week_parser/constants.rb +23 -0
  757. data/lib/studium/utility_scripts/week_parser/help.rb +32 -0
  758. data/lib/studium/utility_scripts/week_parser/menu.rb +59 -0
  759. data/lib/studium/utility_scripts/week_parser/misc.rb +373 -0
  760. data/lib/studium/utility_scripts/week_parser/reset.rb +65 -0
  761. data/lib/studium/utility_scripts/week_parser/run.rb +18 -0
  762. data/lib/studium/utility_scripts/week_parser/show.rb +236 -0
  763. data/lib/studium/utility_scripts/week_parser/week_parser.rb +49 -0
  764. data/lib/studium/utility_scripts/weekday_parser.rb +155 -0
  765. data/lib/studium/utility_scripts/weekly_schedule.rb +198 -0
  766. data/lib/studium/utility_scripts/wochenplanung.rb +261 -0
  767. data/lib/studium/version/version.rb +46 -0
  768. data/lib/studium/www/curriculum_displayer.rb +162 -0
  769. data/lib/studium/www/exams.cgi +54 -0
  770. data/lib/studium/www/fast_ask_exam_question.cgi +156 -0
  771. data/lib/studium/www/handle_curricula/handle_curricula.cgi +154 -0
  772. data/lib/studium/www/next_generation_exam_question_trainer/next_generation_exam_question_trainer.cgi +79 -0
  773. data/lib/studium/www/sinatra/app.rb +231 -0
  774. data/lib/studium/www/sinatra/misc.rb +115 -0
  775. data/lib/studium/www/statistics/statistics.cgi +70 -0
  776. data/lib/studium/yaml/ad_hoc_trainer/README.md +2 -0
  777. data/lib/studium/yaml/ad_hoc_trainer/exam_topics.md +15 -0
  778. data/lib/studium/yaml/allowed_themes_for_exams/allowed_themes_for_exams.yml +347 -0
  779. data/lib/studium/yaml/array_allowed_entries_for_the_file_lecture_information.yml +71 -0
  780. data/lib/studium/yaml/available_exam_topics/available_exam_topics.yml +234 -0
  781. data/lib/studium/yaml/backlog_of_exams.yml +37 -0
  782. data/lib/studium/yaml/colours/custom_colours.yml +28 -0
  783. data/lib/studium/yaml/colours/use_colours.yml +1 -0
  784. data/lib/studium/yaml/current_exams.yml +30 -0
  785. data/lib/studium/yaml/curricula/README.md +39 -0
  786. data/lib/studium/yaml/curricula/bachelor/bachelor_agrarwissenschaften_033255.yml +147 -0
  787. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_basisblock_033630.yml +71 -0
  788. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_botanik_033630.yml +100 -0
  789. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_ecology_033630.yml +74 -0
  790. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_mikrobiologie_und_genetik_033630.yml +122 -0
  791. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_molekulare_biologie_033630.yml +106 -0
  792. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_zoologie_033630.yml +87 -0
  793. data/lib/studium/yaml/curricula/bachelor/bachelor_chemie_033662.yml +165 -0
  794. data/lib/studium/yaml/curricula/bachelor/bachelor_dummy_curriculum.yml +182 -0
  795. data/lib/studium/yaml/curricula/bachelor/bachelor_elektrotechnik_und_informationstechnik_033235.yml +13 -0
  796. data/lib/studium/yaml/curricula/bachelor/bachelor_forstwirtschaft_033225.yml +115 -0
  797. data/lib/studium/yaml/curricula/bachelor/bachelor_informatik_033521.yml +136 -0
  798. data/lib/studium/yaml/curricula/bachelor/bachelor_ktww_033231.yml +84 -0
  799. data/lib/studium/yaml/curricula/bachelor/bachelor_lmbt_033217.yml +121 -0
  800. data/lib/studium/yaml/curricula/bachelor/bachelor_medizinische_informatik_033533.yml +283 -0
  801. data/lib/studium/yaml/curricula/bachelor/bachelor_molekularbiologie_033665.yml +95 -0
  802. data/lib/studium/yaml/curricula/bachelor/bachelor_nutrition_science_033638.yml +119 -0
  803. data/lib/studium/yaml/curricula/bachelor/bachelor_pharmazie_033305.yml +170 -0
  804. data/lib/studium/yaml/curricula/bachelor/bachelor_technische_chemie_033290.yml +131 -0
  805. data/lib/studium/yaml/curricula/bachelor/bachelor_technische_informatik_033535.yml +23 -0
  806. data/lib/studium/yaml/curricula/bachelor/bachelor_ubrm_033227.yml +143 -0
  807. data/lib/studium/yaml/curricula/bachelor/bachelor_verfahrenstechnik_033273.yml +167 -0
  808. data/lib/studium/yaml/curricula/bachelor/bachelor_wirtschaftsinformatik_033526.yml +29 -0
  809. data/lib/studium/yaml/curricula/experimental/bachelor_informatik_in_den_lebenswissenschaften.yml +137 -0
  810. data/lib/studium/yaml/curricula/individual/bachelor_formale_logik.yml +88 -0
  811. data/lib/studium/yaml/curricula/individual/bachelor_informatik_und_molekulare_biologie.yml +1161 -0
  812. data/lib/studium/yaml/curricula/individual/bachelor_vector_based_strategies_in_life_sciences_molecular_medicine_and_biotechnology.yml +1157 -0
  813. data/lib/studium/yaml/curricula/individual/master_bioinformatics_and_nanobiotechnology_in_molecular_medicine.yml +306 -0
  814. data/lib/studium/yaml/curricula/individual/master_vector_based_strategies_in_life_sciences_molecular_medicine_and_biotechnology.yml +741 -0
  815. data/lib/studium/yaml/curricula/master/master_bioinformatik_066875.yml +75 -0
  816. data/lib/studium/yaml/curricula/master/master_biologie_molekulare_mikrobiologie_mikrobielle_oekologie_und_immunbiologie_066830.yml +78 -0
  817. data/lib/studium/yaml/curricula/master/master_biologische_chemie_066863.yml +66 -0
  818. data/lib/studium/yaml/curricula/master/master_dummy_curriculum.yml +197 -0
  819. data/lib/studium/yaml/curricula/master/master_genetik_und_entwicklungsbiologie_066877.yml +89 -0
  820. data/lib/studium/yaml/curricula/master/master_lmbt_066418.yml +112 -0
  821. data/lib/studium/yaml/curricula/master/master_molecular_biology_066865.yml +72 -0
  822. data/lib/studium/yaml/curricula/master/master_molekulare_biologie_066834.yml +151 -0
  823. data/lib/studium/yaml/curricula/master/master_pharmazie_066605.yml +176 -0
  824. data/lib/studium/yaml/curricula/master/master_technische_chemie_066490.yml +123 -0
  825. data/lib/studium/yaml/curricula/outdated/master_bioinformatics_and_molecular_biotechnology_including_aspects_from_molecular_medicine.yml +438 -0
  826. data/lib/studium/yaml/curricula/outdated/master_food_science_and_plant_biotechnology.yml +31 -0
  827. data/lib/studium/yaml/curricula.yml +562 -0
  828. data/lib/studium/yaml/daily_questions_solved.yml +1654 -0
  829. data/lib/studium/yaml/default_delay.yml +4 -0
  830. data/lib/studium/yaml/default_encoding.yml +1 -0
  831. data/lib/studium/yaml/directory_to_the_exam_topics.yml +0 -0
  832. data/lib/studium/yaml/editor.yml +1 -0
  833. data/lib/studium/yaml/exams/next_exams_to_do.md +9 -0
  834. data/lib/studium/yaml/file_for_exam_questions.yml +1 -0
  835. data/lib/studium/yaml/german/README.md +2 -0
  836. data/lib/studium/yaml/german/german_to_english_month_names.yml +16 -0
  837. data/lib/studium/yaml/grouped_themes.yml +192 -0
  838. data/lib/studium/yaml/holidays.yml +201 -0
  839. data/lib/studium/yaml/important_exams.yml +266 -0
  840. data/lib/studium/yaml/inscription_dates_of_universities.yml +60 -0
  841. data/lib/studium/yaml/lecture_aliases.yml +138 -0
  842. data/lib/studium/yaml/lecture_information/lecture_information.yml +61740 -0
  843. data/lib/studium/yaml/log_dir.yml +1 -0
  844. data/lib/studium/yaml/main_topic.yml +11 -0
  845. data/lib/studium/yaml/max_stats.yml +249 -0
  846. data/lib/studium/yaml/meta_themes/README.md +13 -0
  847. data/lib/studium/yaml/meta_themes/biochemistry.md +6 -0
  848. data/lib/studium/yaml/meta_themes/bioinformatics.md +6 -0
  849. data/lib/studium/yaml/meta_themes/biotechnology.md +9 -0
  850. data/lib/studium/yaml/meta_themes/cellbiology.md +9 -0
  851. data/lib/studium/yaml/meta_themes/chemistry.md +9 -0
  852. data/lib/studium/yaml/meta_themes/genetics.md +10 -0
  853. data/lib/studium/yaml/meta_themes/immunology.md +5 -0
  854. data/lib/studium/yaml/meta_themes/metabolic_pathways.md +12 -0
  855. data/lib/studium/yaml/meta_themes/molecular_biology.md +9 -0
  856. data/lib/studium/yaml/meta_themes/protein_engineering.md +10 -0
  857. data/lib/studium/yaml/meta_themes/statistics.md +2 -0
  858. data/lib/studium/yaml/mitbelegung/README.md +4 -0
  859. data/lib/studium/yaml/mitbelegung/mitbelegung.yml +21 -0
  860. data/lib/studium/yaml/mitteilungsbl/303/244tter/mitteilungsbl/303/244tter.yml +363 -0
  861. data/lib/studium/yaml/n_total_questions.yml +1 -0
  862. data/lib/studium/yaml/rename_konsole_tab.yml +1 -0
  863. data/lib/studium/yaml/semester_planner/README.md +4 -0
  864. data/lib/studium/yaml/semester_planner/semester_planner.yml +189 -0
  865. data/lib/studium/yaml/show_topic.yml +1 -0
  866. data/lib/studium/yaml/statistics/lecture_information.yml +1 -0
  867. data/lib/studium/yaml/statistics/max_stats.yml +239 -0
  868. data/lib/studium/yaml/statistics/statistics.yml +75 -0
  869. data/lib/studium/yaml/week/01_monday.yml +25 -0
  870. data/lib/studium/yaml/week/02_tuesday.yml +68 -0
  871. data/lib/studium/yaml/week/03_wednesday.yml +63 -0
  872. data/lib/studium/yaml/week/04_thursday.yml +20 -0
  873. data/lib/studium/yaml/week/05_friday.yml +31 -0
  874. data/lib/studium/yaml/week/06_saturday.yml +16 -0
  875. data/lib/studium/yaml/week/07_sunday.yml +0 -0
  876. data/lib/studium/yaml/week/README.md +10 -0
  877. data/lib/studium.rb +5 -0
  878. data/studium.gemspec +82 -0
  879. data/test/testing_studium.rb +244 -0
  880. data/test/testing_studium_base_class.rb +31 -0
  881. data/test/testing_the_file_lecture_information.rb +18 -0
  882. data/test/testing_time_component.rb +29 -0
  883. metadata +1094 -0
@@ -0,0 +1,3054 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === Studium::Base
6
+ #
7
+ # This is the base class for other classes that are part of the Studium
8
+ # namespace.
9
+ #
10
+ # Not every class needs it though, so it is recommended to only make use
11
+ # of it if you need some "commonly shared functionality".
12
+ #
13
+ # Classes that belong to the Studium::Exams namespace should subclass
14
+ # from this class here.
15
+ # =========================================================================== #
16
+ # To require this base class, do:
17
+ #
18
+ # require 'studium/exams/base.rb'
19
+ #
20
+ # Then, to subclass from it, do:
21
+ #
22
+ # < Studium::Base
23
+ #
24
+ # In a shorter variant combining the two lines above, do this:
25
+ #
26
+ # require 'studium/base/base.rb'; < ::Studium::Base
27
+ #
28
+ # =========================================================================== #
29
+ # require 'studium/base/base.rb'
30
+ # =========================================================================== #
31
+ require 'studium/base/prototype.rb'
32
+
33
+ module Studium
34
+
35
+ class Base # === Studium::Base
36
+
37
+ # require 'studium/base/encoding.rb' # This also pulls in studium/encoding/encoding.rb
38
+ # ========================================================================= #
39
+ # We must support different encodings, so pull in the important files next.
40
+ # ========================================================================= #
41
+ require 'studium/requires/require_encoding.rb'
42
+ require 'studium/requires/require_the_studium_constants.rb'
43
+ # =========================================================================== #
44
+ # Add some important toplevel_methods files next.
45
+ # =========================================================================== #
46
+ require 'studium/toplevel_methods/available_topics.rb'
47
+ require 'studium/toplevel_methods/curriculum_related_code.rb'
48
+ require 'studium/toplevel_methods/does_this_course_require_mandatory_presence.rb'
49
+ require 'studium/toplevel_methods/editor.rb'
50
+ require 'studium/toplevel_methods/esystem.rb'
51
+ require 'studium/toplevel_methods/filter_away_invalid_questions.rb'
52
+ require 'studium/toplevel_methods/find_exam_topic_and_exam_title.rb'
53
+ require 'studium/toplevel_methods/is_on_roebe.rb'
54
+ require 'studium/toplevel_methods/main_dataset.rb'
55
+ require 'studium/toplevel_methods/methods_related_to_files.rb'
56
+ require 'studium/toplevel_methods/methods_related_to_directories.rb'
57
+ require 'studium/toplevel_methods/regexes.rb'
58
+ require 'studium/toplevel_methods/remove_tags.rb'
59
+ require 'studium/toplevel_methods/return_all_exams_on_this_day.rb'
60
+ require 'studium/toplevel_methods/return_local_path_of_this_pwdstud.rb'
61
+ require 'studium/toplevel_methods/return_ects_from_this_lecture_stored_in_the_file_lecture_information.rb'
62
+ require 'studium/toplevel_methods/return_lva_number_of_this_lecture.rb'
63
+ require 'studium/toplevel_methods/return_sanitized_dataset_from_the_file_lecture_information.rb'
64
+ require 'studium/toplevel_methods/find_exam_topic_and_exam_title.rb'
65
+ require 'studium/toplevel_methods/set_this_cd_alias_to.rb'
66
+ require 'studium/toplevel_methods/spacer.rb'
67
+ require 'studium/toplevel_methods/time.rb'
68
+ require 'studium/toplevel_methods/total_ects_points_passed.rb'
69
+ require 'studium/toplevel_methods/url.rb'
70
+ require 'studium/toplevel_methods/write_into_file_related_functionality.rb'
71
+ require 'studium/toplevel_methods/yes_or_no_ja_oder_nein.rb'
72
+ require 'studium/logging/html_log_directory.rb'
73
+ require 'studium/logging/log_directory.rb'
74
+
75
+ begin
76
+ require 'colours/toplevel_methods/misc.rb'
77
+ rescue LoadError; end
78
+
79
+ # ========================================================================= #
80
+ # Add the necessary toplevel_methods:
81
+ # ========================================================================= #
82
+ require 'studium/toplevel_methods/e.rb'
83
+ require 'studium/toplevel_methods/url.rb' # Has Studium.sanitize_url().
84
+
85
+ begin
86
+ require 'opn'
87
+ rescue LoadError; end
88
+
89
+ begin
90
+ require 'open'
91
+ rescue LoadError; end
92
+
93
+ begin
94
+ require 'roebe/requires/require_kde_konsole.rb'
95
+ rescue LoadError; end
96
+
97
+ # ========================================================================= #
98
+ # === COMMON_YEAR_DAYS_IN_MONTH
99
+ #
100
+ # This constant has the days per month, for the whole year.
101
+ #
102
+ # It will not honour leap years properly, though.
103
+ # ========================================================================= #
104
+ COMMON_YEAR_DAYS_IN_MONTH = [
105
+ nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
106
+ ]
107
+
108
+ # ========================================================================= #
109
+ # === UNICODE_RIGHT_ARROW
110
+ # ========================================================================= #
111
+ UNICODE_RIGHT_ARROW = '→'
112
+
113
+ # ========================================================================= #
114
+ # === Base::LEFT_PADDING
115
+ #
116
+ # The default padding (for showing the answer to an exam question) is
117
+ # 4 spaces since as of July 2020. In November 2020 2 spaces are now
118
+ # tried.
119
+ # ========================================================================= #
120
+ LEFT_PADDING = ' ' * 2 # 2 spaces for now.
121
+
122
+ # ========================================================================= #
123
+ # === Base::N_CHARACTERS_PER_LINE
124
+ #
125
+ # If an answer exceeds the following threshold value, then we will chop
126
+ # some bits off of it. The reason why we have defined this here in
127
+ # class Base is because at the least two other classes that are
128
+ # part of the Exam namespace, require this.
129
+ # ========================================================================= #
130
+ N_CHARACTERS_PER_LINE = 78
131
+
132
+ # ========================================================================= #
133
+ # === replace_bold_token_with_default_colour
134
+ #
135
+ # This method can be used to replace <b></b> with the corresponding
136
+ # colour code on the terminal.
137
+ # ========================================================================= #
138
+ def replace_bold_token_with_default_colour(
139
+ i, use_this_colour = :mediumseagreen
140
+ )
141
+ i.gsub(
142
+ /<b>(.+)<\/b>/,
143
+ ::Colours.bold('\1')
144
+ )
145
+ end
146
+
147
+ # ========================================================================= #
148
+ # === replace_all_html_colours_in_this
149
+ #
150
+ # This method will replace all HTML colours, such as <slateblue>, with
151
+ # the corresponding RGB colour variant for the commandline. Typically
152
+ # this refers to a terminal such as the KDE konsole, and a shell such
153
+ # as bash (although other shells are fine too, and many other terminals,
154
+ # such as the gnome-terminal, most likely will work fine as well - but
155
+ # it is optimized for the KDE konsole).
156
+ #
157
+ # This method should only be called after a prior check was done, to
158
+ # determine whether the given input String at hand does indeed
159
+ # include a valid HTML colour. This can be done via a call to
160
+ # the method called line_contains_a_valid_html_colour?().
161
+ # ========================================================================= #
162
+ def replace_all_html_colours_in_this(
163
+ i,
164
+ use_this_colour_for_the_default_colour = colour_for_questions?
165
+ )
166
+ # ======================================================================= #
167
+ # bl $RUBY_COLOURS/toplevel_methods/replace_all_html_colours_in_this_line.rb
168
+ # ======================================================================= #
169
+ ::Colours.replace_all_html_colours_in_this_line(
170
+ i, use_this_colour_for_the_default_colour
171
+ )
172
+ end
173
+
174
+ # ========================================================================= #
175
+ # === colour_for_ects_points
176
+ # ========================================================================= #
177
+ def colour_for_ects_points(i = '')
178
+ ::Studium.colour_for_ects_points(i)
179
+ end; alias colourize_ects colour_for_ects_points # === colourize_ects
180
+ alias colour_ects colour_for_ects_points # === colour_ects
181
+
182
+ # ========================================================================= #
183
+ # === is_a_registered_curriculum?
184
+ # ========================================================================= #
185
+ def is_a_registered_curriculum?(i)
186
+ return ::Studium.is_a_registered_curriculum?(i)
187
+ end
188
+
189
+ # ========================================================================= #
190
+ # === return_opnn
191
+ # ========================================================================= #
192
+ def return_opnn(
193
+ use_this_namespace = NAMESPACE
194
+ )
195
+ ::Colours::GREY+
196
+ use_this_namespace+
197
+ ': '+
198
+ ::Colours::REVERT
199
+ end; alias ropnn return_opnn # === ropnn
200
+
201
+ # ========================================================================= #
202
+ # === spacer
203
+ # ========================================================================= #
204
+ def spacer
205
+ Studium.spacer
206
+ end
207
+
208
+ # ========================================================================= #
209
+ # === set_this_cd_alias_to
210
+ # ========================================================================= #
211
+ def set_this_cd_alias_to(
212
+ cd_alias, new_content, be_verbose = :default
213
+ )
214
+ Studium.set_this_cd_alias_to(cd_alias, new_content, be_verbose)
215
+ end
216
+
217
+ # ========================================================================= #
218
+ # === return_all_exams_on_this_day
219
+ # ========================================================================= #
220
+ def return_all_exams_on_this_day(i)
221
+ Studium.return_all_exams_on_this_day(i)
222
+ end
223
+
224
+ # ========================================================================= #
225
+ # === average_grade
226
+ # ========================================================================= #
227
+ def average_grade(
228
+ i = :default,
229
+ round_to = 2 # ← Round to two numbers.
230
+ )
231
+ require 'studium/exams/average_grade.rb'
232
+ Studium.average_grade(i, round_to)
233
+ end
234
+
235
+ # ========================================================================= #
236
+ # === html_log_dir?
237
+ # ========================================================================= #
238
+ def html_log_directory?
239
+ Studium.html_log_directory?
240
+ end; alias html_log_dir? html_log_directory? # === html_log_dir?
241
+
242
+ # ========================================================================= #
243
+ # === return_local_path_of_this_pwdstud
244
+ # ========================================================================= #
245
+ def return_local_path_of_this_pwdstud(i = 1)
246
+ Studium.return_local_path_of_this_pwdstud(i)
247
+ end
248
+
249
+ # ========================================================================= #
250
+ # === total_ects_points_passed
251
+ # ========================================================================= #
252
+ def total_ects_points_passed(i)
253
+ Studium.total_ects_points_passed(i)
254
+ end
255
+
256
+ # ========================================================================= #
257
+ # === directory_to_my_exam_topics
258
+ # ========================================================================= #
259
+ def directory_to_my_exam_topics
260
+ Studium.directory_to_my_exam_topics
261
+ end
262
+
263
+ # ========================================================================= #
264
+ # === opne
265
+ # ========================================================================= #
266
+ def opne(i)
267
+ opnn; e i
268
+ end
269
+
270
+ # ========================================================================= #
271
+ # === directory_to_the_exam_topics?
272
+ # ========================================================================= #
273
+ def directory_to_the_exam_topics?
274
+ Studium.directory_to_the_exam_topics?
275
+ end; alias path_to_exam_topic? directory_to_the_exam_topics? # === path_to_exam_topic?
276
+ alias directory_of_the_exam_topics? directory_to_the_exam_topics? # === directory_of_the_exam_topics?
277
+
278
+ # ========================================================================= #
279
+ # === be_verbose?
280
+ # ========================================================================= #
281
+ def be_verbose?
282
+ @be_verbose
283
+ end
284
+
285
+ # ========================================================================= #
286
+ # === german_yes_or_no
287
+ # ========================================================================= #
288
+ def german_yes_or_no(i)
289
+ case i
290
+ when true
291
+ 'ja'
292
+ when false
293
+ 'nein'
294
+ end
295
+ end
296
+
297
+ # ========================================================================= #
298
+ # === yes_or_no
299
+ # ========================================================================= #
300
+ def yes_or_no(i)
301
+ case i
302
+ when true
303
+ 'yes'
304
+ when false
305
+ 'no'
306
+ end
307
+ end
308
+
309
+ # ========================================================================= #
310
+ # === set_be_verbose
311
+ # ========================================================================= #
312
+ def set_be_verbose
313
+ @be_verbose = true
314
+ end; alias be_verbose set_be_verbose # === be_verbose
315
+
316
+ # ========================================================================= #
317
+ # === set_be_quiet
318
+ # ========================================================================= #
319
+ def set_be_quiet
320
+ @be_verbose = false
321
+ end
322
+
323
+ # ========================================================================= #
324
+ # === move_file
325
+ # ========================================================================= #
326
+ def move_file(this_file, target)
327
+ FileUtils.mv(this_file, target)
328
+ end
329
+
330
+ # ========================================================================= #
331
+ # === has_this_exam_topic_been_solved?
332
+ # ========================================================================= #
333
+ def has_this_exam_topic_been_solved?(i)
334
+ (Studium.return_n_percent_solved_from_this_topic(i).to_i == 100)
335
+ end
336
+
337
+ # ========================================================================= #
338
+ # === cpruby
339
+ # ========================================================================= #
340
+ def cpruby
341
+ base_dir = ENV['USERS']
342
+ base_dir = '/home' if base_dir.nil?
343
+ path_to_setup_rb_file =
344
+ "#{RUBY_SRC_DIR}roebe/lib/roebe/setup/setup.rb"
345
+ copy(path_to_setup_rb_file, '.')
346
+ end
347
+
348
+ # ========================================================================= #
349
+ # === rinstall2
350
+ # ========================================================================= #
351
+ def rinstall2
352
+ cpruby
353
+ system 'ruby setup.rb --quiet config'
354
+ system 'ruby setup.rb --quiet setup'
355
+ system 'ruby setup.rb --quiet install'
356
+ delete_file 'setup.rb'
357
+ delete_file 'InstalledFiles'
358
+ delete_file '.config'
359
+ end
360
+
361
+ # ========================================================================= #
362
+ # === delete_file
363
+ # ========================================================================= #
364
+ def delete_file(i)
365
+ File.delete(i) if File.exist? i
366
+ end
367
+
368
+ # ========================================================================= #
369
+ # === filter_away_invalid_questions
370
+ #
371
+ # This method will remove entries that begin with '#' and empty entries.
372
+ # ========================================================================= #
373
+ def filter_away_invalid_questions(i)
374
+ Studium.filter_away_invalid_questions(i)
375
+ end
376
+
377
+ # ========================================================================= #
378
+ # === read_in_exam_dataset_from_this_file
379
+ #
380
+ # This is the method that will read from an existing file. If a symbol
381
+ # is given then we will expand this to the default exam-topic directory.
382
+ # ========================================================================= #
383
+ def read_in_exam_dataset_from_this_file(
384
+ this_file
385
+ )
386
+ if this_file.is_a? Symbol
387
+ this_file = "#{exam_topic_directory?}#{this_file}"
388
+ end
389
+ if File.exist? this_file
390
+ dataset = readlines_via_default_encoding(this_file)
391
+ dataset = filter_away_invalid_questions(dataset)
392
+ return dataset
393
+ end
394
+ end
395
+
396
+ # ========================================================================= #
397
+ # === remove_internal_comments
398
+ # ========================================================================= #
399
+ def remove_internal_comments(i)
400
+ if i.is_a? Array
401
+ i.map {|line|
402
+ if line.include? '#'
403
+ line = line[0 .. (line.index('#')-1)]
404
+ end
405
+ line.strip
406
+ }
407
+ end
408
+ end
409
+
410
+ # ========================================================================= #
411
+ # === remove_leading_comments
412
+ # ========================================================================= #
413
+ def remove_leading_comments(i)
414
+ if i.is_a? Array
415
+ i.reject {|line| line.start_with? '#' }
416
+ end
417
+ end
418
+
419
+ # ========================================================================= #
420
+ # === remove_empty_strings
421
+ #
422
+ # This method presently only works on Arrays. We will reject empty
423
+ # Strings from the Array at hand.
424
+ # ========================================================================= #
425
+ def remove_empty_strings(i)
426
+ if i.is_a? Array
427
+ i.reject {|line| line.empty? }
428
+ end
429
+ end
430
+
431
+ # ========================================================================= #
432
+ # === return_all_numbers_from
433
+ #
434
+ # This method will return all numbers from the given input.
435
+ # ========================================================================= #
436
+ def return_all_numbers_from(i)
437
+ return_this = nil
438
+ if i.is_a? Array
439
+ return_this = i.select {|line|
440
+ line =~ /\d+/ # Any entry with a number will be returned.
441
+ }
442
+ end
443
+ return_this
444
+ end
445
+
446
+ # ========================================================================= #
447
+ # === return_all_steop_lectures
448
+ # ========================================================================= #
449
+ def return_all_steop_lectures
450
+ return_sanitized_dataset_from_the_file_lecture_information.select {|a, b|
451
+ is_a_steop_lecture = obtain(:steop, b)
452
+ is_a_steop_lecture
453
+ }
454
+ end
455
+
456
+ # ========================================================================= #
457
+ # === read_this_file_with_default_encoding
458
+ #
459
+ # This method will read in a file, that should ideally exist, in the
460
+ # default project-wide encoding.
461
+ #
462
+ # A few aliases exist to this method, such as "read_this_file()".
463
+ # ========================================================================= #
464
+ def read_this_file_with_default_encoding(
465
+ this_file
466
+ )
467
+ File.read(this_file, encoding: ::Studium.main_encoding?)
468
+ end; alias read_as_string_with_default_encoding read_this_file_with_default_encoding # === read_as_string_with_default_encoding
469
+ alias read_file read_this_file_with_default_encoding # === read_file
470
+ alias read_this_file read_this_file_with_default_encoding # === read_this_file
471
+ alias read_file_with_default_encoding read_this_file_with_default_encoding # === read_file_with_default_encoding
472
+ alias read_in_with_default_encoding read_this_file_with_default_encoding # === read_in_with_default_encoding
473
+
474
+ # ========================================================================= #
475
+ # === file_read_with_proper_encoding
476
+ # ========================================================================= #
477
+ def file_read_with_proper_encoding(this_file)
478
+ Studium.file_read_with_proper_encoding(this_file)
479
+ end
480
+
481
+ # ========================================================================= #
482
+ # === create_file
483
+ # ========================================================================= #
484
+ def create_file(i)
485
+ FileUtils.touch(i)
486
+ end; alias touch create_file # === touch
487
+
488
+ # ========================================================================= #
489
+ # === return_german_weekday_of?
490
+ # ========================================================================= #
491
+ def return_german_weekday_of?(i)
492
+ weekday?(i, :german)
493
+ end
494
+
495
+ # ========================================================================= #
496
+ # === german_date_notation
497
+ #
498
+ # Give a Range as input, and it will give us back a String that
499
+ # shows german date notation, aka DD.MM.YYYY.
500
+ # ========================================================================= #
501
+ def german_date_notation(
502
+ i, use_this_token_as_separator = '-'
503
+ )
504
+ # ======================================================================= #
505
+ # === Handle Range objects next
506
+ # ======================================================================= #
507
+ if i.is_a? Range
508
+ start_date = i.begin
509
+ end_date = i.end
510
+ start_day = start_date.day.to_s.rjust(2, '0')
511
+ start_month = start_date.month.to_s.rjust(2, '0')
512
+ start_year = start_date.year.to_s
513
+ end_day = end_date.day.to_s.rjust(2, '0')
514
+ end_month = end_date.month.to_s.rjust(2, '0')
515
+ end_year = end_date.year.to_s
516
+ i = start_day+'.'+start_month+'.'+start_year+' '+
517
+ use_this_token_as_separator+' '+
518
+ end_day+'.'+end_month+'.'+end_year
519
+ # ======================================================================= #
520
+ # === Handle Time objects next
521
+ #
522
+ # This requires no token.
523
+ # ======================================================================= #
524
+ elsif i.is_a? Time
525
+ i = "#{i.day.to_s.rjust(2, '0')}."\
526
+ "#{i.month.to_s.rjust(2, '0')}."\
527
+ "#{i.year.to_s}"
528
+ end
529
+ return i
530
+ end; alias german_notation german_date_notation # === german_notation
531
+ alias to_german_date german_date_notation # === to_german_date
532
+ alias german_formatting_for_the_date german_date_notation # === german_formatting_for_the_date
533
+
534
+ # ========================================================================= #
535
+ # === show_todays_date
536
+ # ========================================================================= #
537
+ def show_todays_date
538
+ e "Today is the #{slateblue(today?)} (#{lightgreen(weekday?)})"
539
+ e
540
+ end
541
+
542
+ # ========================================================================= #
543
+ # === return_n_questions_were_answered_for_this_topic
544
+ # ========================================================================= #
545
+ def return_n_questions_were_answered_for_this_topic(i)
546
+ Studium::Exams.return_n_questions_were_answered_for_this_topic(i)
547
+ end
548
+
549
+ # ========================================================================= #
550
+ # === day_month_year
551
+ #
552
+ # This method will return a dd.mm.yyyy notation.
553
+ #
554
+ # If you need to find out whether the given input-day is today, then
555
+ # use the method called .is_this_day_today?, defined in this file.
556
+ #
557
+ # An example for this will be:
558
+ #
559
+ # 03.04.2020
560
+ #
561
+ # ========================================================================= #
562
+ def day_month_year(
563
+ use_this_time = Time.now
564
+ )
565
+ if use_this_time.is_a? Time
566
+ use_this_time.strftime('%d.%m.%Y')
567
+ else
568
+ use_this_time
569
+ end
570
+ end; alias today? day_month_year # === today?
571
+ alias return_day_month_year day_month_year # === return_day_month_year
572
+ alias dd_mm_yyyy day_month_year # === dd_mm_yyyy
573
+ alias return_dd_mm_yyyy day_month_year # === return_dd_mm_yyyy
574
+
575
+ # ========================================================================= #
576
+ # === is_this_day_today?
577
+ #
578
+ # This method will return true or false, depending on whether the given
579
+ # input is assumed to be the present day or not.
580
+ #
581
+ # The method assumes that the input will be a Time object normally.
582
+ # ========================================================================= #
583
+ def is_this_day_today?(i = '18.02.2022')
584
+ dd_mm_yyyy(Time.now) == dd_mm_yyyy(i)
585
+ end
586
+
587
+ # ========================================================================= #
588
+ # === return_german_name_for_this_english_month
589
+ # ========================================================================= #
590
+ def return_german_name_for_this_english_month(i)
591
+ array = MONTH_NAME_ALIASES_GERMAN_TO_ENGLISH.invert
592
+ return array[i]
593
+ end
594
+
595
+ # ========================================================================= #
596
+ # === weekdays?
597
+ #
598
+ # This method will return all weekdays, as Array, including german
599
+ # and english names for these weekdays.
600
+ # ========================================================================= #
601
+ def weekdays?
602
+ (
603
+ ARRAY_GERMAN_WEEKDAYS+
604
+ HASH_SHORT_TO_LONG_WEEKDAYS.values
605
+ ).flatten
606
+ end
607
+
608
+ # ========================================================================= #
609
+ # === german_weekdays?
610
+ # ========================================================================= #
611
+ def german_weekdays?
612
+ ARRAY_GERMAN_WEEKDAYS
613
+ end
614
+
615
+ # ========================================================================= #
616
+ # === remove_leading_weekday_names_from
617
+ #
618
+ # Chop away the leading weekday, e. g. "Monday", from the String at hand.
619
+ # ========================================================================= #
620
+ def remove_leading_weekday_names_from(i)
621
+ Studium.remove_leading_weekday_names_from(i)
622
+ end; alias remove_german_weekdays remove_leading_weekday_names_from # === remove_german_weekdays
623
+ alias remove_german_weekdays_from remove_leading_weekday_names_from # === remove_german_weekdays_from
624
+ alias remove_leading_weeknames remove_leading_weekday_names_from # === remove_leading_weeknames
625
+ alias remove_leading_weekdays remove_leading_weekday_names_from # === remove_leading_weekdays
626
+ alias remove_workday_from_this_input remove_leading_weekday_names_from # === remove_workday_from_this_input
627
+ alias remove_german_days remove_leading_weekday_names_from # === remove_german_days
628
+
629
+ # ========================================================================= #
630
+ # === is_on_roebe?
631
+ # ========================================================================= #
632
+ def is_on_roebe?
633
+ Studium.is_on_roebe?
634
+ end; alias is_roebe? is_on_roebe? # === is_roebe?
635
+ alias on_roebe? is_on_roebe? # === on_roebe?
636
+
637
+ # ========================================================================= #
638
+ # === try_to_require_the_rcfiles
639
+ # ========================================================================= #
640
+ def try_to_require_the_rcfiles
641
+ begin
642
+ require 'rcfiles'
643
+ rescue LoadError; end
644
+ end
645
+
646
+ # ========================================================================= #
647
+ # === copy (copy tag)
648
+ # ========================================================================= #
649
+ def copy(from, to)
650
+ if from.is_a? Array
651
+ from.each {|entry|
652
+ copy(entry, to)
653
+ }
654
+ else
655
+ FileUtils.copy(from, to)
656
+ end
657
+ end; alias copy_file copy # === copy_file
658
+
659
+ # ========================================================================= #
660
+ # === set_xorg_buffer
661
+ # ========================================================================= #
662
+ def set_xorg_buffer(i)
663
+ begin
664
+ require 'xorg_buffer' unless Object.const_defined?(:XorgBuffer)
665
+ XorgBuffer.set_buffer(i)
666
+ rescue LoadError
667
+ if is_on_roebe?
668
+ e 'XorgBuffer is not available - can not set the buffer.'
669
+ end
670
+ end
671
+ end
672
+
673
+ # ========================================================================= #
674
+ # === lectures_from_the_individual_vektor_curricula
675
+ #
676
+ # This method is a convenience method, returning all the lectures that
677
+ # belong to the individual bachelor+master vektor-curriculum
678
+ # ========================================================================= #
679
+ def lectures_from_the_individual_vektor_curricula
680
+ (
681
+ obtain_lectures_from_this_curriculum(:bachelor_vektor)+
682
+ obtain_lectures_from_this_curriculum(:master_vektor)
683
+ ).flatten
684
+ end
685
+
686
+ # ========================================================================= #
687
+ # === open_in_editor
688
+ # ========================================================================= #
689
+ def open_in_editor(i)
690
+ Studium.open_in_editor(i)
691
+ end
692
+
693
+ # ========================================================================= #
694
+ # === editor?
695
+ # ========================================================================= #
696
+ def editor?
697
+ Studium.editor?
698
+ end
699
+
700
+ # ========================================================================= #
701
+ # === encoding?
702
+ #
703
+ # This method will return the main encoding in use, by "pointing" towards
704
+ # the constant that keeps track of this.
705
+ # ========================================================================= #
706
+ def encoding?
707
+ ::Studium.main_encoding?
708
+ end; alias main_encoding? encoding? # === main_encoding?
709
+ alias main_encoding_to_use? encoding? # === main_encoding_to_use?
710
+ alias use_this_encoding? encoding? # === use_this_encoding?
711
+ alias encoding_to_use? encoding? # === encoding_to_use?
712
+
713
+ # ========================================================================= #
714
+ # === exit_program (exit tag)
715
+ #
716
+ # Use this method to exit from the program. It is a general "exit-operation"
717
+ # for classes in the Studium project. The reason as to why we don't just
718
+ # simply use exit() is so that we
719
+ # ========================================================================= #
720
+ def exit_program(
721
+ make_newline = :no_newline
722
+ )
723
+ case make_newline
724
+ # ======================================================================= #
725
+ # === :no_newline
726
+ # ======================================================================= #
727
+ when :no_newline
728
+ make_newline = false
729
+ end
730
+ e(N) if make_newline
731
+ exit # Exit here.
732
+ end
733
+
734
+ # ========================================================================= #
735
+ # === turn_this_array_into_the_full_dataset
736
+ #
737
+ # This method accepts an Array of lectures that will be replaced with
738
+ # a full dataset.
739
+ # ========================================================================= #
740
+ def turn_this_array_into_the_full_dataset(
741
+ i, use_this_dataset
742
+ )
743
+ hash = {}
744
+ i.flatten.each {|name_of_the_lecture|
745
+ pointer = use_this_dataset[name_of_the_lecture]
746
+ hash[name_of_the_lecture] = pointer
747
+ }
748
+ hash
749
+ end
750
+
751
+ # ========================================================================= #
752
+ # === no_ext_name
753
+ #
754
+ # This method will return the name of the file (or rather the
755
+ # input given to this method) without extension.
756
+ # ========================================================================= #
757
+ def no_ext_name(i)
758
+ i.sub(/#{File.extname(i)}$/,'')
759
+ end
760
+
761
+ # ========================================================================= #
762
+ # === expand_topic
763
+ #
764
+ # This will expand e. g. 'allgemeine_genetik' to 'Allgemeine Genetik'.
765
+ # ========================================================================= #
766
+ def expand_topic(i)
767
+ Studium.find_corresponding_exam_title(i)
768
+ end; alias find_corresponding_exam_title expand_topic # === find_corresponding_exam_title
769
+
770
+ # ========================================================================= #
771
+ # === cliner (cliner tag)
772
+ #
773
+ # This method can be used such as in the following example, if a specific
774
+ # colour is wanted:
775
+ #
776
+ # cliner('*', :mediumaquamarine)
777
+ #
778
+ # ========================================================================= #
779
+ def cliner(
780
+ which_token_to_use = :default_token,
781
+ use_this_colour = nil,
782
+ &block
783
+ )
784
+ if which_token_to_use.is_a? Hash # Treat Hashes specially.
785
+ # ===================================================================== #
786
+ # === :colours
787
+ # ===================================================================== #
788
+ if which_token_to_use.has_key? :colours
789
+ use_this_colour = which_token_to_use.delete(:colours)
790
+ which_token_to_use = :default_token
791
+ end
792
+ end
793
+ case which_token_to_use
794
+ when :default_token
795
+ which_token_to_use = '='
796
+ end
797
+ # ======================================================================= #
798
+ # === Handle blocks given to this method next
799
+ # ======================================================================= #
800
+ if block_given?
801
+ yielded = yield
802
+ case yielded
803
+ # ===================================================================== #
804
+ # === :unicode
805
+ # ===================================================================== #
806
+ when :unicode
807
+ begin
808
+ require 'roebe/toplevel_methods/unicode/unicode_block_elements.rb'
809
+ which_token_to_use = Roebe.horizontal_double_bar.dup
810
+ rescue LoadError; end
811
+ else
812
+ use_this_colour = :mediumaquamarine
813
+ end
814
+ end
815
+ result = (which_token_to_use * 80)
816
+ if use_this_colour.is_a? Symbol
817
+ if use_this_colour.to_s.include?('konsole_') or
818
+ is_this_colour_a_html_colour?(use_this_colour)
819
+ unless use_this_colour.to_s.include? '_colour_'
820
+ use_this_colour = use_this_colour.to_s
821
+ use_this_colour.sub!(/_/,'_colour_')
822
+ end
823
+ result = COLOURS.send(use_this_colour, result)
824
+ end
825
+ end
826
+ e result
827
+ end
828
+
829
+ # ========================================================================= #
830
+ # === load_yaml_dataset
831
+ #
832
+ # This method should ideally be used whenever a .yml file is to be
833
+ # loaded.
834
+ #
835
+ # The second argument can be used to rescue missing or erroneous
836
+ # yaml files.
837
+ #
838
+ # Invocation example for this is:
839
+ #
840
+ # load_yaml_dataset(:rescue)
841
+ #
842
+ # ========================================================================= #
843
+ def load_yaml_dataset(
844
+ i, do_rescue = false
845
+ )
846
+ case do_rescue
847
+ when :rescue
848
+ do_rescue = true
849
+ end
850
+ if do_rescue
851
+ begin
852
+ YAML.load_file(i)
853
+ rescue LoadError, ArgumentError; end
854
+ else
855
+ YAML.load_file(i)
856
+ end
857
+ end
858
+
859
+ # ========================================================================= #
860
+ # === sanitize_this_topic (sanitize tag, alias tag)
861
+ #
862
+ # This entry keeps all possible aliases to commonly used topics, in
863
+ # particular abbreviations.
864
+ # ========================================================================= #
865
+ def sanitize_this_topic(this_topic)
866
+ Studium.sanitize_this_theme_topic(this_topic)
867
+ end
868
+
869
+ # ========================================================================= #
870
+ # === replace_regular_numbers_with_unicode_numbers
871
+ #
872
+ # This method will replace numbers such as 1 with ¹.
873
+ # ========================================================================= #
874
+ def replace_regular_numbers_with_unicode_numbers(i)
875
+ ::Studium.replace_regular_numbers_with_unicode_numbers(i)
876
+ end
877
+
878
+ # ========================================================================= #
879
+ # === create_directory
880
+ # ========================================================================= #
881
+ def create_directory(i)
882
+ FileUtils.mkdir_p(i)
883
+ end; alias mkdir create_directory # === mkdir
884
+
885
+ # ========================================================================= #
886
+ # === change_directory
887
+ # ========================================================================= #
888
+ def change_directory(
889
+ i = Dir.pwd
890
+ )
891
+ FileUtils.chdir(i)
892
+ end; alias cd change_directory # === cd
893
+
894
+ # ========================================================================= #
895
+ # === return_passed_courses
896
+ #
897
+ # This method will quickly return all passed courses.
898
+ # ========================================================================= #
899
+ def return_passed_courses
900
+ return_dataset_from_file_lecture_information.select {|key, hash|
901
+ hash.has_key?(:already_solved) and
902
+ (hash[:already_solved] == true)
903
+ }
904
+ end
905
+
906
+ # ========================================================================= #
907
+ # === return_ects_points_from_these_lectures
908
+ #
909
+ # Input to this method should be a Hash containing our lectures.
910
+ #
911
+ # An example for this is shown next:
912
+ #
913
+ # {"051010"=>"Programmierung 1",
914
+ # "051110"=>"Mathematische Grundlagen der Informatik 1"}
915
+ #
916
+ # ========================================================================= #
917
+ def return_ects_points_from_these_lectures(hash)
918
+ n_ects_points = 0 # Keep track of the amount of ECTS points here.
919
+ hash.each_pair {|lecture_id, name_of_the_lecture|
920
+ # lecture_id = ensure_main_encoding(lecture_id)
921
+ # name_of_the_lecture = ensure_main_encoding(name_of_the_lecture)
922
+ name_of_the_lecture.squeeze!(' ')
923
+ points = Studium.return_ects_from_this_lecture_stored_in_the_file_lecture_information(
924
+ name_of_the_lecture, lecture_id
925
+ )
926
+ n_ects_points += points
927
+ }
928
+ return n_ects_points
929
+ end
930
+
931
+ # ========================================================================= #
932
+ # === select_lectures_with_this_key
933
+ #
934
+ # This method allows us to select only entries with a particular
935
+ # key. The key has to be passed to the method and - for now - has
936
+ # to be exactly the same as the key (e. g. string for strings
937
+ # and symbols for symbols; no automatic conversions for now).
938
+ #
939
+ # The advantage of this method is that it will simplify a lot of
940
+ # code; all code that requires us to select only specific
941
+ # lectures.
942
+ #
943
+ # Usage examples:
944
+ #
945
+ # .select_lectures_with_this_key(:exam_registration_at)
946
+ # .select_lectures_with_this_key(:already_solved)
947
+ #
948
+ # ========================================================================= #
949
+ def select_lectures_with_this_key(
950
+ searching_for_this_key
951
+ )
952
+ dataset = return_sanitized_dataset_from_the_file_lecture_information
953
+ dataset.select! {|name_of_the_lecture, inner_hash|
954
+ inner_hash.has_key? searching_for_this_key
955
+ } if dataset # <- Must check here, since there may be a nil.
956
+ return dataset
957
+ end
958
+
959
+ # ========================================================================= #
960
+ # === konsole_support?
961
+ # ========================================================================= #
962
+ def konsole_support?
963
+ true
964
+ end
965
+
966
+ # ========================================================================= #
967
+ # === rename_konsole_tab?
968
+ # ========================================================================= #
969
+ def rename_konsole_tab?(
970
+ i = FILE_RENAME_KONSOLE_TAB
971
+ )
972
+ if File.exist? i
973
+ YAML.load_file(i)
974
+ else
975
+ false
976
+ end
977
+ end
978
+
979
+ # ========================================================================= #
980
+ # === return_dataset_for_this_topic
981
+ # ========================================================================= #
982
+ def return_dataset_for_this_topic(i)
983
+ Studium.return_dataset_for_this_topic(i)
984
+ end
985
+
986
+ # ========================================================================= #
987
+ # === rename_kde_konsole_tab
988
+ # ========================================================================= #
989
+ def rename_kde_konsole_tab(
990
+ title = '.'
991
+ )
992
+ if Object.const_defined?(:Roebe) and
993
+ Roebe.respond_to?(:rename_konsole_title_to)
994
+ Roebe.rename_konsole_title_to(title, :be_quiet)
995
+ end
996
+ end
997
+
998
+ # ========================================================================= #
999
+ # === last_file?
1000
+ # ========================================================================= #
1001
+ def last_file?
1002
+ _ = Studium.file_for_exam_questions
1003
+ _ = load_yaml_dataset(_).chomp
1004
+ # ======================================================================= #
1005
+ # If we are on roebe then we will use another path.
1006
+ # ======================================================================= #
1007
+ if is_on_roebe?
1008
+ _ = Studium::MY_EXAM_TOPICS+File.basename(_)
1009
+ end
1010
+ return _
1011
+ end
1012
+
1013
+ # ========================================================================= #
1014
+ # === cheering_person
1015
+ # ========================================================================= #
1016
+ def cheering_person
1017
+ '\o/'
1018
+ end; alias cheering_person? cheering_person # === cheering_person?
1019
+ alias cheering_dude? cheering_person # === cheering_dude?
1020
+
1021
+ # ========================================================================= #
1022
+ # === return_solved_lectures
1023
+ #
1024
+ # This method will return only those entries that have the key
1025
+ # :already_solved set to true.
1026
+ # ========================================================================= #
1027
+ def return_solved_lectures
1028
+ already_solved = select_lectures_with_this_key(:already_solved).select {|a,b|
1029
+ obtain(:already_solved, b) == true
1030
+ }
1031
+ already_solved
1032
+ end
1033
+
1034
+ # ========================================================================= #
1035
+ # === www_connection_is_unavailable
1036
+ # ========================================================================= #
1037
+ def www_connection_is_unavailable
1038
+ @no_connection_to_the_www = true
1039
+ end; alias www_is_unavailable www_connection_is_unavailable # === www_is_unavailable
1040
+
1041
+ # ========================================================================= #
1042
+ # === is_connected_to_the_www?
1043
+ # ========================================================================= #
1044
+ def is_connected_to_the_www?
1045
+ !@no_connection_to_the_www
1046
+ end
1047
+
1048
+ # ========================================================================= #
1049
+ # === sanitize_url
1050
+ #
1051
+ # This is such a useful method that we will use it for all subclasses
1052
+ # of Studium::Base.
1053
+ # ========================================================================= #
1054
+ def sanitize_url(i, optional_extra_modes = nil)
1055
+ Studium.sanitize_url(i, optional_extra_modes)
1056
+ end; alias sanitized_url sanitize_url # === sanitized_url
1057
+
1058
+ # ========================================================================= #
1059
+ # === web_liner
1060
+ # ========================================================================= #
1061
+ def web_liner(this_token = '*')
1062
+ (this_token * 80)+N
1063
+ end
1064
+
1065
+ # ========================================================================= #
1066
+ # === base_dir?
1067
+ #
1068
+ # This is the log dir - where we "operate on".
1069
+ # ========================================================================= #
1070
+ def base_dir?
1071
+ Studium.log_dir?
1072
+ end; alias log_dir? base_dir? # === log_dir?
1073
+
1074
+ # ========================================================================= #
1075
+ # === already_solved_this_lva_number?
1076
+ # ========================================================================= #
1077
+ def already_solved_this_lva_number?(i)
1078
+ Studium.already_solved_this_lva_number?(i)
1079
+ end
1080
+
1081
+ # ========================================================================= #
1082
+ # === return_directory_for
1083
+ #
1084
+ # This method will try to build up the most plausible, local path to
1085
+ # an existing directory.
1086
+ # ========================================================================= #
1087
+ def return_directory_for(
1088
+ name_of_the_lecture, university
1089
+ )
1090
+ Studium.return_directory_for(name_of_the_lecture, university)
1091
+ end
1092
+
1093
+ # ========================================================================= #
1094
+ # === return_steop_lectures (steop tag)
1095
+ #
1096
+ # This method will return all registered STEOP lectures.
1097
+ #
1098
+ # The optional argument will determine whether solved STEOP lectures
1099
+ # will also be returned. By default this is not the case, meaning
1100
+ # that we will ignore STEOP lectures that have already been solved.
1101
+ # ========================================================================= #
1102
+ def return_steop_lectures(
1103
+ optional_ignore_already_completed_steop_lectures = true
1104
+ )
1105
+ if ::Studium.main_dataset?
1106
+ dataset = ::Studium.main_dataset?
1107
+ else
1108
+ dataset = return_dataset_from_the_file_lecture_information
1109
+ end
1110
+ selection = dataset.select {|a, b|
1111
+ b.has_key?(:is_a_steop_lecture) and (b[:is_a_steop_lecture] == true)
1112
+ }
1113
+ if optional_ignore_already_completed_steop_lectures
1114
+ selection = selection.reject {|a, b|
1115
+ b.has_key?(:already_solved) and (b[:already_solved] == true)
1116
+ }
1117
+ end
1118
+ return selection
1119
+ end
1120
+
1121
+ # ========================================================================= #
1122
+ # === remove_newlines
1123
+ #
1124
+ # This method will remove newlines, aka "\n", from Strings and Arrays.
1125
+ # ========================================================================= #
1126
+ def remove_newlines(i)
1127
+ if i.is_a? Array
1128
+ i.map {|entry| remove_newlines(entry) }
1129
+ else
1130
+ i.delete(N)
1131
+ end
1132
+ end
1133
+
1134
+ # ========================================================================= #
1135
+ # === esystem
1136
+ # ========================================================================= #
1137
+ def esystem(i)
1138
+ if i.is_a? Array
1139
+ i.each {|entry| esystem(entry) }
1140
+ else
1141
+ Studium.esystem(i)
1142
+ end
1143
+ end
1144
+
1145
+ # ========================================================================= #
1146
+ # === append_what_into (append tag)
1147
+ #
1148
+ # Use this method to save data into a specific file.
1149
+ # ========================================================================= #
1150
+ def append_what_into(what, into)
1151
+ Studium.append_what_into(what, into)
1152
+ end
1153
+
1154
+ # ========================================================================= #
1155
+ # === ruby_src_dir_at_home?
1156
+ # ========================================================================= #
1157
+ def ruby_src_dir_at_home?
1158
+ Studium.ruby_src_dir_at_home?
1159
+ end
1160
+
1161
+ # ========================================================================= #
1162
+ # === datum?
1163
+ # ========================================================================= #
1164
+ def datum?
1165
+ Studium.datum? # ← Available in "studium/toplevel_methods/time.rb".
1166
+ end
1167
+
1168
+ # ========================================================================= #
1169
+ # === return_n_days_until_sunday
1170
+ # ========================================================================= #
1171
+ def return_n_days_until_sunday(time_now = Time.now)
1172
+ n_days_difference_from_today_to_this_day(time_now, 'Sunday')
1173
+ end
1174
+
1175
+ # ========================================================================= #
1176
+ # === return_either_grey_or_the_custom_colour_for_questions
1177
+ # ========================================================================= #
1178
+ def return_either_grey_or_the_custom_colour_for_questions
1179
+ _ = grey('').strip
1180
+ if @custom_colours and
1181
+ @custom_colours.has_key?('colour_for_questions')
1182
+ _ = COLOURS.send(@custom_colours['colour_for_questions']) { :omit_end }
1183
+ end
1184
+ _
1185
+ end
1186
+
1187
+ # ========================================================================= #
1188
+ # === replace_italic_token_with_default_colour
1189
+ # ========================================================================= #
1190
+ def replace_italic_token_with_default_colour(i, colour_to_use = :royalblue)
1191
+ replace_italic_token_with_this_colour(i, colour_to_use)
1192
+ end
1193
+
1194
+ # ========================================================================= #
1195
+ # === replace_underline_token_with_default_colour
1196
+ # ========================================================================= #
1197
+ def replace_underline_token_with_default_colour(i, colour_to_use = :royalblue)
1198
+ replace_underline_token_with_this_colour(i, colour_to_use)
1199
+ end
1200
+
1201
+ # ========================================================================= #
1202
+ # === replace_underline_token_with_this_colour
1203
+ #
1204
+ # We can use either <ud> or <u>, so we have to check for both variants.
1205
+ # ========================================================================= #
1206
+ def replace_underline_token_with_this_colour(
1207
+ i, use_this_colour = :royalblue # This default colour is rarely in use.
1208
+ )
1209
+ if (i.include?('<ud>') and i.include?('</ud>')) or
1210
+ (i.include?('<u>') and i.include?('</u>'))
1211
+ # ===================================================================== #
1212
+ # Next, set up a non-greedy explicit regex:
1213
+ #
1214
+ # https://rubular.com/r/uNnBwWc35LKjXX
1215
+ #
1216
+ # ===================================================================== #
1217
+ use_this_regex = /<ud?>([-a-züöäA-ZÜÖÄ0-9\/%, \n\.]+?)<\/ud?>/
1218
+ i = i.dup if i.frozen?
1219
+ i.gsub!(
1220
+ use_this_regex,
1221
+ ::Colours.string_underline('\1')+
1222
+ ::Colours.remove_trailing_escape_code(
1223
+ ::Colours.send(use_this_colour.to_sym, '')
1224
+ )
1225
+ )
1226
+ end
1227
+ return i
1228
+ end
1229
+
1230
+ # ========================================================================= #
1231
+ # === replace_italic_token_with_this_colour
1232
+ #
1233
+ # This method can be used to replace <i></i> with the corresponding
1234
+ # colour code on the terminal.
1235
+ # ========================================================================= #
1236
+ def replace_italic_token_with_this_colour(
1237
+ i, use_this_colour = :mediumseagreen
1238
+ )
1239
+ use_this_regex = /<it?>([A-Za-zöäüÖÄÜ\s]+)<\/it?>/ # See: https://rubular.com/r/mZb1ZtGHCLhg2U
1240
+ i.gsub(
1241
+ use_this_regex,
1242
+ ::Colours.string_italic('\1')+
1243
+ ::Colours.remove_trailing_escape_code(
1244
+ ::Colours.send(use_this_colour.to_sym, '')
1245
+ )
1246
+ )+
1247
+ ::Colours.send(use_this_colour,'')
1248
+ end
1249
+
1250
+ # ========================================================================= #
1251
+ # === return_the_remote_homepage_url
1252
+ #
1253
+ # The first parameter denotes which particular lecture is to be
1254
+ # investigated, in regards to its homepage-URL.
1255
+ #
1256
+ # The second parameter should contain the hash-dataset that is to be
1257
+ # used.
1258
+ # ========================================================================= #
1259
+ def return_the_remote_homepage_url(
1260
+ of_this_lecture, dataset_to_use
1261
+ )
1262
+ of_this_lecture.strip!
1263
+ _ = dataset_to_use
1264
+ if _.has_key? :homepage
1265
+ _ = _[:homepage]
1266
+ else
1267
+ e "No :homepage entry for `#{sfancy(of_this_lecture.to_s)}`."
1268
+ end
1269
+ _
1270
+ end
1271
+
1272
+ # ========================================================================= #
1273
+ # === roebe_exam_directory?
1274
+ # ========================================================================= #
1275
+ def roebe_exam_directory?
1276
+ "#{RUBY_STUDIUM_HOME_DIR}exam_topics/"
1277
+ end
1278
+
1279
+ # ========================================================================= #
1280
+ # === remove_tags_from_this_input
1281
+ #
1282
+ # This method will return all HTML-like tags from the given input String.
1283
+ # ========================================================================= #
1284
+ def remove_tags_from_this_input(i)
1285
+ return Studium.remove_tags(i)
1286
+ end; alias remove_tags remove_tags_from_this_input # === remove_tags
1287
+
1288
+ # ========================================================================= #
1289
+ # === write_what_into
1290
+ #
1291
+ # Use this method to save data into a specific file.
1292
+ # ========================================================================= #
1293
+ def write_what_into(
1294
+ what, into, &block
1295
+ )
1296
+ Studium.write_what_into(what, into, &block)
1297
+ end; alias store_what_into write_what_into # === store_what_into
1298
+
1299
+ # ========================================================================= #
1300
+ # === return_sanitized_dataset_from_the_file_lecture_information
1301
+ #
1302
+ # This method will return the dataset stored in the file
1303
+ # 'lecture_information.yml'.
1304
+ # ========================================================================= #
1305
+ def return_sanitized_dataset_from_the_file_lecture_information
1306
+ Studium.return_sanitized_dataset_from_the_file_lecture_information
1307
+ end; alias return_dataset_from_the_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_dataset_from_the_file_lecture_information
1308
+ alias return_dataset_from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_dataset_from_file_lecture_information
1309
+ alias lecture_information_dataset return_sanitized_dataset_from_the_file_lecture_information # === lecture_information_dataset
1310
+ alias lecture_information return_sanitized_dataset_from_the_file_lecture_information # === lecture_information_dataset
1311
+ alias dataset_from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === dataset_from_file_lecture_information
1312
+ alias dataset_from_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === dataset_from_lecture_information
1313
+ alias dataset_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === dataset_lecture_information
1314
+ alias return_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_lecture_information
1315
+ alias return_data_from_the_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_data_from_the_file_lecture_information
1316
+ alias return_all_lectures return_sanitized_dataset_from_the_file_lecture_information # === return_all_lectures
1317
+ alias return_lectures_from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_lectures_from_file_lecture_information
1318
+ alias dataset_from_the_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === dataset_from_the_file_lecture_information
1319
+ alias return_sanitized_dataset_from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_sanitized_dataset_from_file_lecture_information
1320
+ alias return_dataset_from_the_lectures return_sanitized_dataset_from_the_file_lecture_information # === return_dataset_from_the_lectures
1321
+ alias return_sanitized_dataset return_sanitized_dataset_from_the_file_lecture_information # === return_sanitized_dataset
1322
+ alias return_all_lectures_from_the_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_all_lectures_from_the_file_lecture_information
1323
+ alias return_dataset_from_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === return_dataset_from_lecture_information
1324
+ alias from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === from_file_lecture_information
1325
+ alias sanitized_dataset_from_file_lecture_information return_sanitized_dataset_from_the_file_lecture_information # === sanitized_dataset_from_file_lecture_information
1326
+
1327
+ # ========================================================================= #
1328
+ # === obtain (obtain tag)
1329
+ #
1330
+ # This method will attempt to return the entry point of our main hash.
1331
+ #
1332
+ # It is optimized towards the dataset stored in the file
1333
+ # 'lecture_information.yml'.
1334
+ #
1335
+ # Typical usage example:
1336
+ #
1337
+ # curricula = obtain(:curricula, pointer_to_the_lecture_dataset)
1338
+ #
1339
+ # ========================================================================= #
1340
+ def obtain(
1341
+ this_key, hash, be_verbose = true
1342
+ )
1343
+ if block_given?
1344
+ yielded = yield
1345
+ case yielded
1346
+ # ===================================================================== #
1347
+ # === :be_quiet
1348
+ # ===================================================================== #
1349
+ when :be_quiet
1350
+ be_verbose = false
1351
+ end
1352
+ end
1353
+ case be_verbose
1354
+ when :be_quiet,
1355
+ :be_silent
1356
+ be_verbose = false
1357
+ end
1358
+ # ======================================================================= #
1359
+ # The following case menu will make use of some common popular aliases
1360
+ # or typos.
1361
+ # ======================================================================= #
1362
+ case this_key
1363
+ # ======================================================================= #
1364
+ # === :passed_when
1365
+ # ======================================================================= #
1366
+ when :passed_when,
1367
+ :solved_at
1368
+ this_key = :already_solved_at
1369
+ # ======================================================================= #
1370
+ # === :passed_successfully
1371
+ # ======================================================================= #
1372
+ when :passed_successfully
1373
+ this_key = :already_solved
1374
+ # ======================================================================= #
1375
+ # === :steop
1376
+ # ======================================================================= #
1377
+ when :steop,
1378
+ 'steop'
1379
+ this_key = :is_a_steop_lecture
1380
+ # ======================================================================= #
1381
+ # === :curricula_entries
1382
+ # ======================================================================= #
1383
+ when :curricula_entries,
1384
+ :curricula,
1385
+ 'curricula'
1386
+ this_key = 'curricula'
1387
+ # ======================================================================= #
1388
+ # === :english_description
1389
+ # ======================================================================= #
1390
+ when :english_description
1391
+ this_key = :description_in_english
1392
+ # ======================================================================= #
1393
+ # === :german_description
1394
+ # ======================================================================= #
1395
+ when :german_description
1396
+ this_key = :description_in_german
1397
+ # ======================================================================= #
1398
+ # === :this_university
1399
+ # ======================================================================= #
1400
+ when :this_university,
1401
+ :university
1402
+ this_key = :university
1403
+ # ======================================================================= #
1404
+ # === :n_ects
1405
+ # ======================================================================= #
1406
+ when :n_ects, :n_ects_points
1407
+ this_key = :ects
1408
+ # ======================================================================= #
1409
+ # === :curricula_ids
1410
+ # ======================================================================= #
1411
+ when :curricula_ids,
1412
+ :curriculum_id
1413
+ this_key = 'curricula'
1414
+ # ======================================================================= #
1415
+ # === :lecturers
1416
+ # ======================================================================= #
1417
+ when :lecturers
1418
+ this_key = 'lecturers'
1419
+ # ======================================================================= #
1420
+ # === :semester
1421
+ # ======================================================================= #
1422
+ when 'homepage',
1423
+ :remote_url
1424
+ this_key = :homepage
1425
+ # ======================================================================= #
1426
+ # === :semester
1427
+ # ======================================================================= #
1428
+ when :semester, 'semester'
1429
+ this_key = :semester
1430
+ end
1431
+ # ======================================================================= #
1432
+ # Work on any other symbols given to us next.
1433
+ # ======================================================================= #
1434
+ if this_key.is_a? Symbol
1435
+ if hash.has_key? this_key
1436
+ # All is fine.
1437
+ elsif hash.has_key? this_key.to_s
1438
+ # Else use that String as key instead.
1439
+ this_key = this_key.to_s
1440
+ end
1441
+ end
1442
+ if hash.is_a? Symbol
1443
+ e "Symbol called :#{slateblue(hash.to_s)}"
1444
+ e swarn('This is not allowed - please correct this. '\
1445
+ '(Read the next line in how to do so.)')
1446
+ e swarn('This method requires (1) first the key, (2) then the Hash.')
1447
+ exit
1448
+ elsif hash.is_a?(Hash) and hash.has_key?(this_key)
1449
+ hash[this_key] # Return this.
1450
+ else
1451
+ if be_verbose
1452
+ case this_key
1453
+ when :is_a_steop_lecture
1454
+ # Exceptions - these keys ^^^ will NOT be shown.
1455
+ else
1456
+ e "In file #{sfile('base.rb')}, method: obtain() → No key found, "\
1457
+ "called `#{this_key.to_s}` (class '#{this_key.class.to_s})"
1458
+ e 'The hash was:'
1459
+ e
1460
+ pp hash
1461
+ e
1462
+ end
1463
+ end
1464
+ nil
1465
+ end
1466
+ end; alias obtain_this_value_from_hash obtain # === obtain_this_value_from_hash
1467
+ alias obtain_from obtain # === obtain_from
1468
+
1469
+ # ========================================================================= #
1470
+ # === opnn
1471
+ #
1472
+ # The method also handles blocks.
1473
+ # ========================================================================= #
1474
+ def opnn(
1475
+ i = @namespace,
1476
+ &block
1477
+ )
1478
+ if use_opn?
1479
+ if i.is_a? String # "Turn" it into a Hash here.
1480
+ i = { namespace: i }
1481
+ end
1482
+ Opn.opn(i, &block)
1483
+ end
1484
+ end
1485
+
1486
+ # ========================================================================= #
1487
+ # === enable_debug
1488
+ # ========================================================================= #
1489
+ def enable_debug
1490
+ @debug = true
1491
+ end; alias do_debug enable_debug # === do_debug
1492
+
1493
+ # ========================================================================= #
1494
+ # === debug?
1495
+ # ========================================================================= #
1496
+ def debug?
1497
+ @debug
1498
+ end
1499
+
1500
+ # ========================================================================= #
1501
+ # === be_silent
1502
+ # ========================================================================= #
1503
+ def be_silent
1504
+ @be_verbose = false
1505
+ end; alias be_quiet be_silent # === be_quiet
1506
+
1507
+ # ========================================================================= #
1508
+ # === is_a_weekday?
1509
+ #
1510
+ # This method will return true if the input is a String that represents
1511
+ # a weekday, such as "Monday". Otherwise, false will be returned.
1512
+ #
1513
+ # Both german and english variants are allowed here.
1514
+ # ========================================================================= #
1515
+ def is_a_weekday?(i = 'Montag')
1516
+ result = false
1517
+ if ARRAY_GERMAN_WEEKDAYS.include? i
1518
+ result = true
1519
+ elsif ARRAY_ENGLISH_WEEKDAYS.include? i
1520
+ result = true
1521
+ end
1522
+ return result
1523
+ end
1524
+
1525
+ # ========================================================================= #
1526
+ # === do_not_be_verbose
1527
+ # ========================================================================= #
1528
+ def do_not_be_verbose
1529
+ @be_verbose = false
1530
+ end
1531
+
1532
+ # ========================================================================= #
1533
+ # === @use_opn
1534
+ # ========================================================================= #
1535
+ def use_opn?
1536
+ @use_opn
1537
+ end
1538
+
1539
+ # ========================================================================= #
1540
+ # === do_not_use_opn
1541
+ # ========================================================================= #
1542
+ def do_not_use_opn
1543
+ @use_opn = false
1544
+ end
1545
+
1546
+ # ========================================================================= #
1547
+ # === studium_directory_at_home?
1548
+ # ========================================================================= #
1549
+ def studium_directory_at_home?
1550
+ Studium.studium_directory_at_home?
1551
+ end; alias studium_directory_at_home? studium_directory_at_home? # === studium_directory_at_home?
1552
+
1553
+ # ========================================================================= #
1554
+ # === is_this_a_valid_html_colour?
1555
+ #
1556
+ # This method will let us know whether the given input is a valid (aka
1557
+ # registered) "html colour". An example for this would be the String
1558
+ # 'slateblue'.
1559
+ # ========================================================================= #
1560
+ def is_this_a_valid_html_colour?(i)
1561
+ ::Studium.is_this_a_valid_html_colour?(i)
1562
+ end; alias is_this_colour_a_html_colour? is_this_a_valid_html_colour? # === is_this_colour_a_html_colour?
1563
+
1564
+ # ========================================================================= #
1565
+ # === eparse
1566
+ #
1567
+ # The colours for this method are defined within the method body.
1568
+ #
1569
+ # We could also delegate to ::Colours.eparse() instead.
1570
+ # ========================================================================= #
1571
+ def eparse(i)
1572
+ if use_colours?
1573
+ token = '#'
1574
+ if i.include? token
1575
+ splitted = i.split(token)
1576
+ splitted[-1] = olive(splitted[-1])
1577
+ i = splitted.join(royalblue(token))
1578
+ end
1579
+ end
1580
+ e i
1581
+ end
1582
+
1583
+ # ========================================================================= #
1584
+ # === colourize_percentage
1585
+ #
1586
+ # This method should be used when we wish to display percentage
1587
+ # values on the commandline.
1588
+ # ========================================================================= #
1589
+ def colourize_percentage(i)
1590
+ return seagreen(i) if use_colours? # Used to be cadetblue.
1591
+ return i
1592
+ end
1593
+
1594
+ # ========================================================================= #
1595
+ # === remove_escape_sequences
1596
+ # ========================================================================= #
1597
+ def remove_escape_sequences(i)
1598
+ ::Colours.remove_escape_sequences(i)
1599
+ end
1600
+
1601
+ # ========================================================================= #
1602
+ # === this_month_has_n_days?
1603
+ #
1604
+ # This method will return the maximum amount of days in the given
1605
+ # month.
1606
+ # ========================================================================= #
1607
+ def this_month_has_n_days?(
1608
+ this_month,
1609
+ this_year = Time.now.year
1610
+ )
1611
+ this_month = this_month.to_i
1612
+ return 29 if this_month == 2 && Date.gregorian_leap?(this_year)
1613
+ COMMON_YEAR_DAYS_IN_MONTH[this_month]
1614
+ end
1615
+
1616
+ # ========================================================================= #
1617
+ # === return_dd_mm_yy_and_time_from
1618
+ #
1619
+ # This method will return the day, in dd.mm.yyyy format, and the
1620
+ # time on that date. You have to pass in a special object to this
1621
+ # method, such as an instance of class Time - see methods used
1622
+ # such as .day() or .month() and so forth.
1623
+ # ========================================================================= #
1624
+ def return_dd_mm_yy_and_time_from(i)
1625
+ Studium.return_dd_mm_yy_and_time_from(i)
1626
+ end
1627
+
1628
+ require 'studium/toplevel_methods/word_wrap.rb'
1629
+ # ========================================================================= #
1630
+ # === word_wrap
1631
+ #
1632
+ # This method can re-arrange a given text (a String) to honour a certain
1633
+ # size limit, such as 80 characters per line.
1634
+ #
1635
+ # Keep in mind that colours that may be used inside of a tag, such as
1636
+ # <tomato>foobar</tomato>, will also count for that limit. This has
1637
+ # to be remembered when doing the calculation for text-wrapping.
1638
+ # ========================================================================= #
1639
+ def word_wrap(
1640
+ text,
1641
+ line_width = N_CHARACTERS_PER_LINE
1642
+ )
1643
+ ::Studium.word_wrap(text, line_width)
1644
+ end
1645
+
1646
+ # ========================================================================= #
1647
+ # === vertical_bar?
1648
+ # ========================================================================= #
1649
+ def vertical_bar?
1650
+ return '|'
1651
+ end
1652
+
1653
+ # ========================================================================= #
1654
+ # === horizontal_bar?
1655
+ # ========================================================================= #
1656
+ def horizontal_bar?
1657
+ return '―'
1658
+ end
1659
+
1660
+ # ========================================================================= #
1661
+ # === shall_we_make_use_of_unicode_symbols?
1662
+ #
1663
+ # The most common idiom for using this method is actually via:
1664
+ #
1665
+ # if use_unicode_symbols?
1666
+ #
1667
+ # ========================================================================= #
1668
+ def shall_we_make_use_of_unicode_symbols?
1669
+ ::Studium.shall_we_make_use_of_unicode_symbols?
1670
+ end; alias use_unicode_symbols? shall_we_make_use_of_unicode_symbols? # === use_unicode_symbols?
1671
+ alias use_unicode? shall_we_make_use_of_unicode_symbols? # === use_unicode?
1672
+
1673
+ # ========================================================================= #
1674
+ # === unicode_blocks_line
1675
+ #
1676
+ # This method will "draw" a (horizontal) unicode-blocks line, that is,
1677
+ # a line that is "built" from unicode blocks.
1678
+ #
1679
+ # The optional first argument can be used to use a specific colour.
1680
+ #
1681
+ # Usage examples:
1682
+ #
1683
+ # unicode_blocks_line :steelblue
1684
+ # unicode_blocks_line(:steelblue) {{ n_tokens: 84 }}
1685
+ #
1686
+ # ========================================================================= #
1687
+ def unicode_blocks_line(
1688
+ optional_use_this_colour = nil,
1689
+ use_n_tokens = :default, # <- This defaults to 78.
1690
+ use_this_unicode_token = :upper_half_block
1691
+ )
1692
+ case use_n_tokens
1693
+ when :default # Must come before we check for a given block.
1694
+ use_n_tokens = 78
1695
+ end
1696
+ if block_given?
1697
+ yielded = yield
1698
+ if yielded.is_a? Hash
1699
+ if yielded.has_key? :n_tokens
1700
+ use_n_tokens = yielded.delete(:n_tokens)
1701
+ end
1702
+ end
1703
+ end
1704
+ begin
1705
+ require 'roebe/toplevel_methods/unicode/unicode_block_elements.rb'
1706
+ rescue LoadError; end
1707
+ _ = (Roebe.send(use_this_unicode_token) * use_n_tokens)
1708
+ if optional_use_this_colour
1709
+ _ = ::Colours::AllColourMethods.send(optional_use_this_colour, _)
1710
+ end
1711
+ return _
1712
+ end
1713
+
1714
+ # ========================================================================= #
1715
+ # === return_hh_mm_ss_from
1716
+ #
1717
+ # Input to this method may be like this:
1718
+ #
1719
+ # 2020-03-04 00:00:00 +0000
1720
+ #
1721
+ # It will then return the ss:mm:hh notation.
1722
+ # ========================================================================= #
1723
+ def return_hh_mm_ss_from(i)
1724
+ if i.is_a? String
1725
+ i = Time.parse(i)
1726
+ end
1727
+ if i.is_a? Time
1728
+ "#{i.hour.to_s.rjust(2,'0')}:"\
1729
+ "#{i.min.to_s.rjust(2,'0')}:"\
1730
+ "#{i.sec.to_s.rjust(2,'0')}"
1731
+ else
1732
+ e 'Unknown time format.'
1733
+ end
1734
+ end; alias hh_mm_ss return_hh_mm_ss_from # === hh_mm_ss
1735
+
1736
+ # ========================================================================= #
1737
+ # === hh_mm_ss_dd_mm_yyyy
1738
+ # ========================================================================= #
1739
+ def hh_mm_ss_dd_mm_yyyy(i)
1740
+ "#{hh_mm_ss(i)}-#{dd_mm_yyyy(i)}"
1741
+ end
1742
+
1743
+ # ========================================================================= #
1744
+ # === german_weekday?
1745
+ #
1746
+ # This method will return a german weekday, for the given input. The
1747
+ # input should be the specific wday at hand.
1748
+ # ========================================================================= #
1749
+ def german_weekday?(
1750
+ i = Date.today.wday
1751
+ )
1752
+ weekday?(i, :german)
1753
+ end; alias weekday_at german_weekday? # === weekday_at
1754
+ alias german_weekday german_weekday? # === german_weekday
1755
+
1756
+ # ========================================================================= #
1757
+ # === directory_to_the_exam_topics?
1758
+ #
1759
+ # This method will point to the directory where all exam topics
1760
+ # are normally kept; it is simply a "wrapper-method".
1761
+ # ========================================================================= #
1762
+ def directory_to_the_exam_topics?
1763
+ Studium.directory_to_the_exam_topics?
1764
+ end; alias exam_topics_directory? directory_to_the_exam_topics? # === exam_topics_directory?
1765
+ alias exam_topic_directory? directory_to_the_exam_topics? # === exam_topic_directory?
1766
+
1767
+ # ========================================================================= #
1768
+ # === lectures_from_indi1
1769
+ # ========================================================================= #
1770
+ def lectures_from_indi1
1771
+ obtain_lectures_from_this_curriculum(:indi1)
1772
+ end
1773
+
1774
+ # ========================================================================= #
1775
+ # === lectures_from_indi2
1776
+ # ========================================================================= #
1777
+ def lectures_from_indi2
1778
+ obtain_lectures_from_this_curriculum(:indi2)
1779
+ end
1780
+
1781
+ # ========================================================================= #
1782
+ # === lectures_from_indi3
1783
+ # ========================================================================= #
1784
+ def lectures_from_indi3
1785
+ obtain_lectures_from_this_curriculum(:indi3)
1786
+ end
1787
+
1788
+ # ========================================================================= #
1789
+ # === lectures_from_indi4
1790
+ # ========================================================================= #
1791
+ def lectures_from_indi4
1792
+ obtain_lectures_from_this_curriculum(:indi4)
1793
+ end
1794
+
1795
+ # ========================================================================= #
1796
+ # === return_random_curriculum
1797
+ # ========================================================================= #
1798
+ def return_random_curriculum
1799
+ ::Studium.return_random_curriculum
1800
+ end
1801
+
1802
+ # ========================================================================= #
1803
+ # === lectures_from_the_bachelor_genetik_curriculum
1804
+ # ========================================================================= #
1805
+ def lectures_from_the_bachelor_genetik_curriculum
1806
+ obtain_lectures_from_this_curriculum(:bachelor_genetik_curriculum)
1807
+ end
1808
+
1809
+ # ========================================================================= #
1810
+ # === return_lectures_from_bachelor_vektor_curriculum
1811
+ # ========================================================================= #
1812
+ def return_lectures_from_bachelor_vektor_curriculum
1813
+ obtain_lectures_from_this_curriculum(:bachelor_vektor)
1814
+ end
1815
+
1816
+ # ========================================================================= #
1817
+ # === convert_this_array_of_lectures_into_the_full_dataset
1818
+ #
1819
+ # The purpose of this method is to turn an Array that holds Strings
1820
+ # such as "941111 Genetische Ressourcen von Nutzpflanzen" into the
1821
+ # corresponding dataset.
1822
+ #
1823
+ # This method will return a Hash if everything went fine.
1824
+ # ========================================================================= #
1825
+ def convert_this_array_of_lectures_into_the_full_dataset(i)
1826
+ if i.is_a? Array
1827
+ if Studium.main_dataset?.nil?
1828
+ Studium.initialize_main_dataset
1829
+ end
1830
+ _ = Studium.main_dataset?
1831
+ hash = {}
1832
+ i.map {|course_id_and_course_name|
1833
+ if _.has_key?(course_id_and_course_name)
1834
+ hash[course_id_and_course_name] = _[course_id_and_course_name]
1835
+ end
1836
+ }
1837
+ hash
1838
+ else
1839
+ raise 'This method only accepts an Array as input.'
1840
+ end
1841
+ end
1842
+
1843
+ # ========================================================================= #
1844
+ # === weekday?
1845
+ #
1846
+ # This method will return a String such as "Thursday". Note that the
1847
+ # english name will be returned by default. This can be changed via
1848
+ # the second parameter to this method, which can be either :english
1849
+ # or :german.
1850
+ #
1851
+ # The input to this method should be a number, such as can be obtained
1852
+ # via the method .wday().
1853
+ #
1854
+ # A String can also be passed into this method, in a form like
1855
+ # "dd.mm.yyyy". So, an input String such as "10.03.2018" is
1856
+ # perfectly valid.
1857
+ # ========================================================================= #
1858
+ def weekday?(
1859
+ i = Date.today.wday,
1860
+ use_this_language = :english
1861
+ )
1862
+ if i.is_a?(String) and i.include?('.')
1863
+ # ===================================================================== #
1864
+ # In this case here assume an input-String such as "12.03.2018".
1865
+ # ===================================================================== #
1866
+ begin
1867
+ i = Time.parse(i).wday
1868
+ rescue ArgumentError => error
1869
+ pp error
1870
+ end
1871
+ end
1872
+ result = Date::DAYNAMES[i]
1873
+ case use_this_language
1874
+ # ======================================================================= #
1875
+ # === :german
1876
+ # ======================================================================= #
1877
+ when :german,
1878
+ :use_german
1879
+ # ===================================================================== #
1880
+ # In this case we have to translate to the german name.
1881
+ # ===================================================================== #
1882
+ result = ENGLISH_TO_GERMAN_WEEKDAYS[result]
1883
+ end
1884
+ return result
1885
+ end; alias return_name_for_this_day weekday? # === return_name_for_this_day
1886
+ alias return_weekday_for weekday? # === return_weekday_for
1887
+ alias return_weekday_of weekday? # === return_weekday_of
1888
+ alias return_weekday_from_this_input weekday? # === return_weekday_from_this_input
1889
+ alias english_weekday weekday? # === english_weekday
1890
+ alias english_weekday? weekday? # === english_weekday?
1891
+
1892
+ # ========================================================================= #
1893
+ # === remove_weekday_names_from
1894
+ #
1895
+ # This method will remove Strings such as "Monday" or "Montag" from
1896
+ # the given input argument.
1897
+ # ========================================================================= #
1898
+ def remove_weekday_names_from(i)
1899
+ Studium.remove_weekday_names_from(i)
1900
+ end; alias remove_weekname_from remove_weekday_names_from # === remove_weekname_from
1901
+ alias remove_weekdays remove_weekday_names_from # === remove_weekdays
1902
+ alias remove_weekday_names_from remove_weekday_names_from # === remove_weekday_names_from
1903
+ alias remove_weeknames_from remove_weekday_names_from # === remove_weeknames_from
1904
+ alias remove_weeknames remove_weekday_names_from # === remove_weeknames
1905
+ alias remove_weekday_name remove_weekday_names_from # === remove_weekday_name
1906
+
1907
+ # ========================================================================= #
1908
+ # === return_hour_from_this
1909
+ #
1910
+ # This method will extract the time-format from a String,
1911
+ # such as:
1912
+ #
1913
+ # "18.02.2020, 17:00-18:00"
1914
+ # "Dienstag 13.10.2020, 14:30-17:45"
1915
+ #
1916
+ # A String will be returned in this event, holding the start and
1917
+ # stop time - for instance, in the first example it would return
1918
+ # the String "17:00-18:00".
1919
+ #
1920
+ # A String should be given as argument to this method.
1921
+ # ========================================================================= #
1922
+ def return_hour_from_this(i)
1923
+ i.scan(
1924
+ /\d{2}:\d{2}-\d{2}:\d{2}/
1925
+ ).flatten.first.to_s.strip
1926
+ end; alias extract_the_time_from return_hour_from_this # === extract_the_time
1927
+
1928
+ # ========================================================================= #
1929
+ # === sort_these_lecture_names_by_time
1930
+ # ========================================================================= #
1931
+ def sort_these_lecture_names_by_time(
1932
+ array, weekday
1933
+ )
1934
+ _ = main_dataset?
1935
+ array.sort_by {|entry|
1936
+ pointer = _[entry]
1937
+ lva_date = pointer['lva_dates'].select {|inner_entry|
1938
+ inner_entry.include? weekday
1939
+ }
1940
+ lva_date = lva_date.first if lva_date.is_a? Array
1941
+ lva_date = return_hour_from_this(lva_date) # This will be like "08:00-09:45"
1942
+ # ===================================================================== #
1943
+ # However had, we only need the last part, so chop it down.
1944
+ # ===================================================================== #
1945
+ if lva_date.include? '-'
1946
+ lva_date = lva_date.split('-').first
1947
+ end
1948
+ timestamp = Time.parse(lva_date)
1949
+ timestamp # And "return" it here.
1950
+ }
1951
+ end
1952
+
1953
+ # ========================================================================= #
1954
+ # === number_to_month
1955
+ #
1956
+ # This method will convert a number, such as 6, to the corresponding
1957
+ # month entry.
1958
+ # ========================================================================= #
1959
+ def number_to_month(i)
1960
+ array = Date::MONTHNAMES
1961
+ i = i.to_i
1962
+ return array[i]
1963
+ end
1964
+
1965
+ # ========================================================================= #
1966
+ # === return_this_line_has_n_characters_as_html_colour_tags
1967
+ # ========================================================================= #
1968
+ def return_this_line_has_n_characters_as_html_colour_tags(i)
1969
+ i.scan(REGEX_FOR_OPENING_AND_CLOSING_COLOUR_TAGS).map {|entry|
1970
+ entry.size
1971
+ }.sum
1972
+ end
1973
+
1974
+ # ========================================================================= #
1975
+ # === does_this_line_include_a_html_colour?
1976
+ # ========================================================================= #
1977
+ def does_this_line_include_a_html_colour?(i)
1978
+ ::Colours.does_this_line_include_a_html_colour?(i)
1979
+ end
1980
+
1981
+ # ========================================================================= #
1982
+ # === translate_dd_mm_yyyy_to_weekday
1983
+ #
1984
+ # This method will return the weekday of a given dd.mm.yyyy date.
1985
+ #
1986
+ # If the given input is, for example, the String '25.02.2019', then
1987
+ # this method will return the String 'Monday'.
1988
+ # ========================================================================= #
1989
+ def translate_dd_mm_yyyy_to_weekday(
1990
+ i = '25.02.2020'
1991
+ )
1992
+ weekday?(i)
1993
+ end; alias translate_dd_mm_yyy_to_weekday translate_dd_mm_yyyy_to_weekday # === translate_dd_mm_yyy_to_weekday
1994
+
1995
+ # ========================================================================= #
1996
+ # === return_name_of_the_weekday
1997
+ #
1998
+ # This method can be used to return an associated weekday to a specific
1999
+ # date, such as '22.02.2018'. The format has to be in dd.mm.yyyy.
2000
+ #
2001
+ # As mnemonic-helper, Roebe.return_german_weekday "22.11.2022" would
2002
+ # yield the String "Dienstag".
2003
+ # ========================================================================= #
2004
+ def return_name_of_the_weekday(
2005
+ i = :today
2006
+ )
2007
+ begin
2008
+ require 'roebe/constants/time.rb'
2009
+ rescue LoadError; end
2010
+ case i
2011
+ # ======================================================================= #
2012
+ # === :today
2013
+ # ======================================================================= #
2014
+ when :today
2015
+ i = Roebe.return_german_weekday(i) if Object.const_defined? :Roebe
2016
+ end
2017
+ if i.include? ','
2018
+ splitted = i.split(',')
2019
+ first = splitted.first
2020
+ if first.count('.') > 1
2021
+ return Roebe.return_german_weekday(first) if Object.const_defined? :Roebe
2022
+ end
2023
+ else
2024
+ return i
2025
+ end
2026
+ end; alias return_weekday return_name_of_the_weekday # === return_weekday
2027
+
2028
+ # ========================================================================= #
2029
+ # === return_month_fitting_to_this_input
2030
+ #
2031
+ # This method will return a number.
2032
+ # ========================================================================= #
2033
+ def return_month_fitting_to_this_input(i)
2034
+ i = i.capitalize
2035
+ if MONTH_NAME_TO_MONTH_NUMBER.has_key? i
2036
+ i = MONTH_NAME_TO_MONTH_NUMBER[i]
2037
+ end
2038
+ return i.to_i
2039
+ end
2040
+
2041
+ # ========================================================================= #
2042
+ # === extract_dd_mm_yyyy
2043
+ #
2044
+ # This method can be used to extract the dd.mm.yyyy format from the given
2045
+ # input at hand. It will discard everything else.
2046
+ #
2047
+ # So, for instance, if the input is "15.10.2018, 09:00-18:00" then
2048
+ # this method will return only "15.10.2018".
2049
+ # ========================================================================= #
2050
+ def extract_dd_mm_yyyy(i)
2051
+ i =~ /(\d{1,2}\.\d{1,2}\.\d{4})/ # This will also generate a match.
2052
+ $1.to_s.dup
2053
+ end; alias extract_ddmmyyyy extract_dd_mm_yyyy # === extract_ddmmyyyy
2054
+
2055
+ # ========================================================================= #
2056
+ # === has_year_entry?
2057
+ #
2058
+ # This method will return a Boolean.
2059
+ #
2060
+ # It will return true if the line has a year entry such as '2018'; and
2061
+ # it will return false, otherwise.
2062
+ # ========================================================================= #
2063
+ def has_year_entry?(this_line)
2064
+ this_line =~ /\d{4}/ # If this line has at the least one entry with 4 numbers.
2065
+ end; alias this_line_has_a_year_entry? has_year_entry? # === has_year_entry?
2066
+
2067
+ # ========================================================================= #
2068
+ # === return_n_days_until_monday
2069
+ # ========================================================================= #
2070
+ def return_n_days_until_monday(
2071
+ time_now = Time.now
2072
+ )
2073
+ n_days_difference_from_today_to_this_day(time_now, 'Monday')
2074
+ end
2075
+
2076
+ # ========================================================================= #
2077
+ # === n_days_difference_from_today_to_this_day
2078
+ #
2079
+ # This method will return a number, which is the amount of days between
2080
+ # weekdays.
2081
+ #
2082
+ # The days are numbered like this:
2083
+ #
2084
+ # Monday: 1
2085
+ # Tuesday: 2
2086
+ # Wednesday: 3
2087
+ # Thursday: 4
2088
+ # Friday: 5
2089
+ # Saturday: 6
2090
+ # Sunday: 0
2091
+ #
2092
+ # So, how to calculate the time difference to the next day?
2093
+ #
2094
+ # Well, say we have the current day be a Wednesday, and the day that is
2095
+ # to be compared, a Friday. The difference is thus (5 - 3 = 2). If the
2096
+ # current day is a Saturday, and the input-day is a Friday, then
2097
+ # the difference must be 5.
2098
+ #
2099
+ # If we have, for example, "Friday" to "Tuesday", the this method
2100
+ # should return the number 4, because the distance is that: Friday,
2101
+ # Saturday, Sunday and Monday (the start day has to be included, as
2102
+ # lectures can happen on that day still, e. g. if you check early
2103
+ # in the morning, you could still have courses in the evening
2104
+ # slots scheduled).
2105
+ # ========================================================================= #
2106
+ def n_days_difference_from_today_to_this_day(
2107
+ time_now = Time.now,
2108
+ name_of_the_future_day # ← This ought to be a String, such as "Monday".
2109
+ )
2110
+ n_days_difference = 0
2111
+ weekday_as_number = time_now.wday
2112
+ name_of_the_future_day = name_of_the_future_day.dup if name_of_the_future_day.frozen?
2113
+ name_of_the_future_day.strip! # We better strip that input.
2114
+ start_day = Date::DAYNAMES[weekday_as_number]
2115
+ # ======================================================================= #
2116
+ # The next is simply a hardcoded table. We will begin with the
2117
+ # future day.
2118
+ # ======================================================================= #
2119
+ n_days_difference =
2120
+ case start_day
2121
+ when 'Monday'
2122
+ case name_of_the_future_day
2123
+ when 'Tuesday' then 1
2124
+ when 'Wednesday' then 2
2125
+ when 'Thursday' then 3
2126
+ when 'Friday' then 4
2127
+ when 'Saturday' then 5
2128
+ when 'Sunday' then 6
2129
+ end
2130
+ when 'Tuesday'
2131
+ case name_of_the_future_day
2132
+ when 'Wednesday' then 1
2133
+ when 'Thursday' then 2
2134
+ when 'Friday' then 3
2135
+ when 'Saturday' then 4
2136
+ when 'Sunday' then 5
2137
+ when 'Monday' then 6
2138
+ end
2139
+ when 'Wednesday'
2140
+ case name_of_the_future_day
2141
+ when 'Thursday' then 1
2142
+ when 'Friday' then 2
2143
+ when 'Saturday' then 3
2144
+ when 'Sunday' then 4
2145
+ when 'Monday' then 5
2146
+ when 'Tuesday' then 6
2147
+ end
2148
+ when 'Thursday'
2149
+ case name_of_the_future_day
2150
+ when 'Friday' then 1
2151
+ when 'Saturday' then 2
2152
+ when 'Sunday' then 3
2153
+ when 'Monday' then 4
2154
+ when 'Tuesday' then 5
2155
+ when 'Wednesday' then 6
2156
+ end
2157
+ when 'Friday'
2158
+ case name_of_the_future_day
2159
+ when 'Saturday' then 1
2160
+ when 'Sunday' then 2
2161
+ when 'Monday' then 3
2162
+ when 'Tuesday' then 4
2163
+ when 'Wednesday' then 5
2164
+ when 'Thursday' then 6
2165
+ end
2166
+ when 'Saturday'
2167
+ case name_of_the_future_day
2168
+ when 'Sunday' then 1
2169
+ when 'Monday' then 2
2170
+ when 'Tuesday' then 3
2171
+ when 'Wednesday' then 4
2172
+ when 'Thursday' then 5
2173
+ when 'Friday' then 6
2174
+ end
2175
+ when 'Sunday'
2176
+ case name_of_the_future_day
2177
+ when 'Monday' then 1
2178
+ when 'Tuesday' then 2
2179
+ when 'Wednesday' then 3
2180
+ when 'Thursday' then 4
2181
+ when 'Friday' then 5
2182
+ when 'Saturday' then 6
2183
+ end
2184
+ end
2185
+ return n_days_difference
2186
+ end
2187
+
2188
+ # ========================================================================= #
2189
+ # === return_lva_number_of_this_lecture
2190
+ # ========================================================================= #
2191
+ def return_lva_number_of_this_lecture(this_lecture)
2192
+ ::Studium.return_lva_number_of_this_lecture(this_lecture)
2193
+ end
2194
+
2195
+ # ========================================================================= #
2196
+ # === csv_file?
2197
+ # ========================================================================= #
2198
+ def csv_file?
2199
+ FILE_PASSED_EXAMS_PER_MONTH
2200
+ end
2201
+
2202
+ # ========================================================================= #
2203
+ # === do_these_curricula_include_both_a_bachelor_and_a_master_curriculum?(i)
2204
+ #
2205
+ # The input to this method should be an Array.
2206
+ # ========================================================================= #
2207
+ def do_these_curricula_include_both_a_bachelor_and_a_master_curriculum?(i)
2208
+ result = false
2209
+ if i.any? {|entry| entry.start_with?('033')} and
2210
+ i.any? {|entry| entry.start_with?('066')}
2211
+ result = true
2212
+ end
2213
+ return result
2214
+ end
2215
+
2216
+ # ========================================================================= #
2217
+ # === from_curriculum_id_to_university
2218
+ #
2219
+ # This method will translate from the curriculum-ID to the university.
2220
+ # So it will return a String such as "BOKU".
2221
+ # ========================================================================= #
2222
+ def from_curriculum_id_to_university(id)
2223
+ ::Studium.from_curriculum_id_to_university(id)
2224
+ end; alias from_curriculum_number_to_university from_curriculum_id_to_university # === from_curriculum_number_to_university
2225
+ alias which_university? from_curriculum_id_to_university # === which_university?
2226
+
2227
+ # ========================================================================= #
2228
+ # === return_name_of_this_curriculum_based_on_its_id_number
2229
+ #
2230
+ # The input to this method should be the ID of a curriculum number,
2231
+ # ideally as a String, such as '033290'.
2232
+ # ========================================================================= #
2233
+ def return_name_of_this_curriculum_based_on_its_id_number(i)
2234
+ ::Studium.map_curriculum_number_to_curriculum_name(i)
2235
+ end; alias from_curriculum_id_to_curriculum_name return_name_of_this_curriculum_based_on_its_id_number # === from_curriculum_id_to_curriculum_name
2236
+ alias return_curriculum_name_of_this_curriculum_number return_name_of_this_curriculum_based_on_its_id_number # === return_curriculum_name_of_this_curriculum_number
2237
+ alias curriculum_number_to_curriculum_name return_name_of_this_curriculum_based_on_its_id_number # === curriculum_number_to_curriculum_name
2238
+ alias name_of_this_curriculum? return_name_of_this_curriculum_based_on_its_id_number # === name_of_this_curriculum?
2239
+ alias return_name_of_the_curriculum_based_on_this_curriculum_id return_name_of_this_curriculum_based_on_its_id_number # === return_name_of_the_curriculum_based_on_this_curriculum_id
2240
+ alias return_name_of_the_curriculum return_name_of_this_curriculum_based_on_its_id_number # === return_name_of_the_curriculum
2241
+ alias turn_id_to_curriculum_name return_name_of_this_curriculum_based_on_its_id_number # === turn_id_to_curriculum_name
2242
+
2243
+ # ========================================================================= #
2244
+ # === return_all_bachelor_lectures
2245
+ #
2246
+ # This method will simply return all bachelor-lectures.
2247
+ # ========================================================================= #
2248
+ def return_all_bachelor_lectures(
2249
+ from_this_dataset = ::Studium.main_dataset?
2250
+ )
2251
+ if from_this_dataset.nil?
2252
+ ::Studium.initialize_main_dataset
2253
+ from_this_dataset = ::Studium.main_dataset?
2254
+ end
2255
+ from_this_dataset.select {|name_of_the_lecture, inner_hash|
2256
+ array = inner_hash['curricula']
2257
+ is_a_bachelor_lecture?(array)
2258
+ }
2259
+ end
2260
+
2261
+ # ========================================================================= #
2262
+ # === return_either_grey_or_the_custom_colour_for_answers
2263
+ # ========================================================================= #
2264
+ def return_either_grey_or_the_custom_colour_for_answers
2265
+ _ = grey('').strip
2266
+ if @custom_colours and
2267
+ @custom_colours.has_key?('colour_for_answers')
2268
+ _ = COLOURS.send(@custom_colours['colour_for_answers']) { :omit_end }
2269
+ end
2270
+ _
2271
+ end
2272
+
2273
+ # ========================================================================= #
2274
+ # === bachelor_master_or_diploma
2275
+ #
2276
+ # For a given solved lecture, we will determine whether it belongs
2277
+ # to a Bachelor (B), Master (M) or Diploma (D) curriculum.
2278
+ #
2279
+ # For the line:
2280
+ #
2281
+ # 13.05.2020 | 1.0 | 1.0 | 1 | BOKU | M | SE | 940003 | 2020S | Emerging Topics in RNA Biology (in Eng.)
2282
+ # 0 1 2 3 4 5
2283
+ #
2284
+ # It would be at 5.
2285
+ # ========================================================================= #
2286
+ def bachelor_master_or_diploma(
2287
+ this_lecture, dataset = nil
2288
+ )
2289
+ if dataset.nil? and File.exist? FILE_PASSED_EXAMS_PER_MONTH
2290
+ dataset = File.readlines(FILE_PASSED_EXAMS_PER_MONTH).reject {|line|
2291
+ line.strip.empty? or
2292
+ line.strip.start_with?('#')
2293
+ }
2294
+ end
2295
+ selection = dataset.select {|line|
2296
+ splitted = this_lecture.split(' ')
2297
+ lecture_id = splitted.first
2298
+ course_name = splitted[1..-1].join(' ').strip
2299
+ line.include?(lecture_id) and
2300
+ line.include?(course_name)
2301
+ }
2302
+ if selection.empty?
2303
+ '(unknown)'
2304
+ else
2305
+ selection = selection.first
2306
+ return selection.split('|')[5].strip
2307
+ end
2308
+ end
2309
+
2310
+ # ========================================================================= #
2311
+ # === return_name_of_this_curriculum
2312
+ #
2313
+ # This method will return the official name of a curriculum. In order
2314
+ # to achieve this, the method will read the file, and grab the second
2315
+ # line, which should contain the name of the curriculum at hand.
2316
+ #
2317
+ # This method will NOT remove strings such as "Bachelorcurriculum"
2318
+ # or "Mastercurriculum", due to the individual vector-curriculum
2319
+ # having the very same name (Bachelor + Master).
2320
+ # ========================================================================= #
2321
+ def return_name_of_this_curriculum(i)
2322
+ file = return_file_for_this_curriculum(i)
2323
+ if file.nil?
2324
+ e 'Something went wrong for the input '+steelblue(i)+'.'
2325
+ e 'No match could be found for it. Are you sure that it must exist?'
2326
+ exit
2327
+ elsif File.exist? file
2328
+ dataset = readlines_with_proper_encoding(file)
2329
+ name = dataset[1].delete('#=').strip
2330
+ return name
2331
+ end
2332
+ end; alias return_long_name_of_this_curriculum return_name_of_this_curriculum # === return_long_name_of_this_curriculum
2333
+
2334
+ # ========================================================================= #
2335
+ # === rds
2336
+ # ========================================================================= #
2337
+ def rds(i)
2338
+ i.squeeze('/')
2339
+ end
2340
+
2341
+ # ========================================================================= #
2342
+ # === return_all_registered_curricula
2343
+ # ========================================================================= #
2344
+ def return_all_registered_curricula
2345
+ Studium.return_registered_standalone_curricula
2346
+ end
2347
+
2348
+ # ========================================================================= #
2349
+ # === return_dataset_from_this_curriculum_file
2350
+ # ========================================================================= #
2351
+ def return_dataset_from_this_curriculum_file(i)
2352
+ return Studium.return_dataset_from_this_curriculum_file(i)
2353
+ end; alias return_dataset_for_this_curriculum_file return_dataset_from_this_curriculum_file # === return_dataset_for_this_curriculum_file
2354
+ alias return_dataset_from_this_curriculum return_dataset_from_this_curriculum_file # === return_dataset_from_this_curriculum
2355
+ alias return_this_curriculum return_dataset_from_this_curriculum_file # === return_this_curriculum
2356
+
2357
+ # ========================================================================= #
2358
+ # === ensure_that_the_log_directory_exists
2359
+ #
2360
+ # This method will try to make sure that the log directory exists.
2361
+ # ========================================================================= #
2362
+ def ensure_that_the_log_directory_exists
2363
+ _ = log_dir?
2364
+ unless File.directory? _
2365
+ mkdir(_)
2366
+ end
2367
+ unless File.directory? _+'html/'
2368
+ mkdir("#{_}html/")
2369
+ end
2370
+ end
2371
+
2372
+ # ========================================================================= #
2373
+ # === has_a_bachelor_and_a_master_curriculum?
2374
+ # ========================================================================= #
2375
+ def has_a_bachelor_and_a_master_curriculum?(i)
2376
+ has_a_bachelor_curriculum?(i) and has_a_master_curriculum?(i)
2377
+ end
2378
+
2379
+ # ========================================================================= #
2380
+ # === available_topics_as_short_name
2381
+ # ========================================================================= #
2382
+ def available_topics_as_short_name
2383
+ ::Studium::Exams.all_topics_as_short_name.sort
2384
+ end; alias available_topics? available_topics_as_short_name # === available_topics?
2385
+ alias exam_topics? available_topics_as_short_name # === exam_topics?
2386
+ alias return_all_exam_topics available_topics_as_short_name # === return_all_exam_topics
2387
+ alias available_exam_topics? available_topics_as_short_name # === available_exam_topics?
2388
+
2389
+ # ========================================================================= #
2390
+ # === find_corresponding_exam_topic
2391
+ #
2392
+ # This method will find the corresponding exam topic, based on a short
2393
+ # input. For example, "bem1" will be short for basic biochemistry.
2394
+ # ========================================================================= #
2395
+ def find_corresponding_exam_topic(i)
2396
+ Studium.find_corresponding_exam_topic(i)
2397
+ end; alias return_file_associated_with_this_exam_topic find_corresponding_exam_topic # === return_file_associated_with_this_exam_topic
2398
+
2399
+ # ========================================================================= #
2400
+ # === return_n_exam_questions_in
2401
+ #
2402
+ # This method will return how many exam questions are in the given topic
2403
+ # xyz.
2404
+ # ========================================================================= #
2405
+ def return_n_exam_questions_in(this_topic)
2406
+ Studium::Exams.return_n_questions_in_this_topic(this_topic)
2407
+ end
2408
+
2409
+ # ========================================================================= #
2410
+ # === file_lecture_information?
2411
+ # ========================================================================= #
2412
+ def file_lecture_information?
2413
+ ::Studium.file_lecture_information?
2414
+ end
2415
+
2416
+ # ========================================================================= #
2417
+ # === infer_the_namespace
2418
+ #
2419
+ # This will assume the true namespace from the inspectable name.
2420
+ # ========================================================================= #
2421
+ def infer_the_namespace
2422
+ _ = inspect.to_s.delete('<')
2423
+ if _.include? ' '
2424
+ _ = _.split(' ').first.delete('#')
2425
+ if _.include? ':'
2426
+ _ = _.split(':')[0 .. -2].reject {|entry| entry.empty? }.join('::')
2427
+ end
2428
+ end
2429
+ @namespace = _ # And assign it here.
2430
+ end
2431
+
2432
+ # ========================================================================= #
2433
+ # === left_arrow
2434
+ # ========================================================================= #
2435
+ def left_arrow?
2436
+ '←'
2437
+ end; alias left_arrow left_arrow? # === left_arrow
2438
+
2439
+ # ========================================================================= #
2440
+ # === is_prüfungsimmanent?
2441
+ #
2442
+ # This method can determine whether a course is "prüfungsimmanent",
2443
+ # aka whether this course requires continuous, mandatory presence
2444
+ # (of the student).
2445
+ #
2446
+ # The argument to this method should be the type of the lecture at
2447
+ # hand, such as "VO" or "VU" or "SE" or "PR", as a String.
2448
+ #
2449
+ # The method will always return a boolean value, aka true or
2450
+ # false. If true is the return value then this means that "yes,
2451
+ # this course requires mandatory presence".
2452
+ # ========================================================================= #
2453
+ def is_prüfungsimmanent?(
2454
+ i, ignore_these_types = nil
2455
+ )
2456
+ Studium.is_prüfungsimmanent?(i, ignore_these_types)
2457
+ end; alias is_a_prüfungsimmanent_course? is_prüfungsimmanent? # === is_a_prüfungsimmanent_course?
2458
+ alias is_this_a_prüfungsimment_course? is_prüfungsimmanent? # === is_this_a_prüfungsimment_course?
2459
+ alias is_this_a_prüfungsimmanent_course? is_prüfungsimmanent? # === is_this_a_prüfungsimmanent_course?
2460
+
2461
+ # ========================================================================= #
2462
+ # === right_arrow?
2463
+ # ========================================================================= #
2464
+ def right_arrow?
2465
+ UNICODE_RIGHT_ARROW
2466
+ end; alias right_arrow right_arrow? # === right_arrow
2467
+ alias rarrow right_arrow? # === rarrow
2468
+ alias rarrow? right_arrow? # === rarrow?
2469
+
2470
+ # ========================================================================= #
2471
+ # === return_current_year
2472
+ #
2473
+ # This method will simply return the current year, as String.
2474
+ # ========================================================================= #
2475
+ def return_current_year
2476
+ Time.now.year.to_s
2477
+ end; alias current_year? return_current_year # === current_year?
2478
+
2479
+ # ========================================================================= #
2480
+ # === current_semester?
2481
+ #
2482
+ # This method will either return the Symbol :summer or it will return
2483
+ # the Symbol :winter. This will be based on the current time (today).
2484
+ # ========================================================================= #
2485
+ def current_semester?
2486
+ today = ::Time.now
2487
+ # ======================================================================= #
2488
+ # Next we must determine whether we have the Range in winter or the
2489
+ # Range in summer.
2490
+ # ======================================================================= #
2491
+ current_year = current_year?.to_i
2492
+ next_year = current_year+1
2493
+ winter_range = ( Date.parse('01.10.'+current_year.to_s) .. Date.parse('28.02.'+next_year.to_s) )
2494
+ min_winter_day = winter_range.min
2495
+ max_winter_day = winter_range.max
2496
+ summer_range = ( Date.parse('01.03.'+current_year.to_s) .. Date.parse('30.09.'+current_year.to_s) )
2497
+ min_summer_day = summer_range.min
2498
+ max_summer_day = summer_range.max
2499
+ # ======================================================================= #
2500
+ # Ok, we have all the required dates. Now we have to check on the variable
2501
+ # today to find out in which range we are in.
2502
+ # ======================================================================= #
2503
+ if min_winter_day <= today.to_datetime and max_winter_day >= today.to_datetime
2504
+ # e 'Yes, the queried date is part of the date-range.'
2505
+ :winter
2506
+ else
2507
+ # e 'No, the queried date is NOT part of the date-range.'
2508
+ if min_summer_day <= today.to_datetime and max_summer_day >= today.to_datetime
2509
+ :summer
2510
+ else
2511
+ :impossible_situation_check_for_flaw_in_the_code
2512
+ end
2513
+ end
2514
+ end
2515
+
2516
+ # ========================================================================= #
2517
+ # === has_lva_dates_registered?
2518
+ # ========================================================================= #
2519
+ def has_lva_dates_registered?(i)
2520
+ return false if i.nil? or i.empty? # Reject impossible values quickly.
2521
+ if i.is_a?(Array) and !i.empty?
2522
+ true
2523
+ else
2524
+ false
2525
+ end
2526
+ end; alias has_any_lva_dates_registered? has_lva_dates_registered? # === has_any_lva_dates_registered?
2527
+
2528
+ # ========================================================================= #
2529
+ # === select_for_prüfungsimmanente_LVs
2530
+ #
2531
+ # We assume the input to this method is a Hash containing all lectures.
2532
+ # ========================================================================= #
2533
+ def select_for_prüfungsimmanente_LVs(i)
2534
+ i.select {|name_of_the_course, inner_hash|
2535
+ type = inner_hash[:type]
2536
+ is_prüfungsimmanent?(type)
2537
+ }
2538
+ end
2539
+
2540
+ # ========================================================================= #
2541
+ # === return_lectures_with_at_the_least_one_upcoming_exam
2542
+ #
2543
+ # This method will return all lectures that have at the least
2544
+ # one upcoming exam entry. In this context "upcoming" refers
2545
+ # to an exam date that comes after today (or any day before
2546
+ # today).
2547
+ # ========================================================================= #
2548
+ def return_lectures_with_at_the_least_one_upcoming_exam
2549
+ today = Time.now
2550
+ return_sanitized_dataset_from_the_file_lecture_information.select {|name_of_the_course, hash_dataset|
2551
+ if hash_dataset.has_key? 'exams'
2552
+ exams = hash_dataset['exams']
2553
+ if exams.is_a? Array
2554
+ exams = exams.first
2555
+ end
2556
+ exams = remove_german_weekdays(exams)
2557
+ exams.delete!(',')
2558
+ if exams.include? 'Ort:'
2559
+ exams = exams.split('Ort:').first.to_s
2560
+ end
2561
+ # =================================================================== #
2562
+ # The next line can be problematic, if the entry is incorrect.
2563
+ # Hence the rescue-clause.
2564
+ # =================================================================== #
2565
+ begin
2566
+ time_parsed = Time.parse(exams)
2567
+ rescue Exception => error
2568
+ pp error
2569
+ e rev+'The original input was: '+
2570
+ tomato(hash_dataset['exams'])
2571
+ e 'The modified input was: '+
2572
+ steelblue(exams)
2573
+ exit
2574
+ end
2575
+ today < time_parsed # Check that the courses are not too old.
2576
+ else
2577
+ false
2578
+ end
2579
+ }
2580
+ end
2581
+
2582
+ # ========================================================================= #
2583
+ # === read_dataset_from_a_curriculum_file
2584
+ # ========================================================================= #
2585
+ def read_dataset_from_a_curriculum_file(
2586
+ i,
2587
+ optional_commands = :remove_comments
2588
+ )
2589
+ Studium.read_dataset_from_a_curriculum_file(i, optional_commands)
2590
+ end
2591
+
2592
+ require 'studium/toplevel_methods/is_this_lecture_a_practical_course.rb'
2593
+ # ========================================================================= #
2594
+ # === is_this_lecture_a_practical_course?
2595
+ # ========================================================================= #
2596
+ def is_this_lecture_a_practical_course?(
2597
+ this_lecture,
2598
+ optional_lecture_type = nil
2599
+ )
2600
+ ::Studium.is_this_lecture_a_practical_course?(this_lecture, optional_lecture_type)
2601
+ end; alias is_this_lecture_a_practical_course is_this_lecture_a_practical_course? # === is_this_lecture_a_practical_course
2602
+ alias is_it_a_practical_course? is_this_lecture_a_practical_course? # === is_it_a_practical_course?
2603
+
2604
+ # ========================================================================= #
2605
+ # === beautiful_url
2606
+ #
2607
+ # This method can be used to "beautify" a remote URL, based on shorter
2608
+ # input.
2609
+ #
2610
+ # Until 10.12.2019 this method exclusively used BeautifulUrl.
2611
+ #
2612
+ # Since as of 10.12.2019, this method will actually tap into
2613
+ # Studium.return_url_from() if it is registered.
2614
+ # ========================================================================= #
2615
+ def beautiful_url(i)
2616
+ unless Studium.respond_to? :is_this_url_registered?
2617
+ # ===================================================================== #
2618
+ # Enable support for that .rb file next.
2619
+ # ===================================================================== #
2620
+ require 'studium/toplevel_methods/return_remote_homepage_of_this_lecture.rb'
2621
+ end
2622
+ if Studium.is_this_url_registered?(i)
2623
+ i = Studium.return_url_from(i)
2624
+ else
2625
+ i = BeautifulUrl[i]
2626
+ end
2627
+ if i.is_a? Array
2628
+ i = i.first
2629
+ end
2630
+ return i
2631
+ end; alias return_remote_URL beautiful_url # === return_remote_URL
2632
+
2633
+ # ========================================================================= #
2634
+ # === has_a_bachelor_curriculum?
2635
+ #
2636
+ # This method will return true if the given Array has any bachelor
2637
+ # curriculum; and it will return false otherwise.
2638
+ # ========================================================================= #
2639
+ def has_a_bachelor_curriculum?(array)
2640
+ Studium.has_a_bachelor_curriculum?(array)
2641
+ end; alias has_a_bachelor_curriculum_entry? has_a_bachelor_curriculum? # === has_a_bachelor_curriculum_entry?
2642
+ alias is_a_bachelor_lecture? has_a_bachelor_curriculum? # === is_a_bachelor_curriculum?
2643
+ alias is_a_bachelor_curriculum? has_a_bachelor_curriculum? # === is_a_bachelor_curriculum?
2644
+ alias does_this_include_a_bachelor_curriculum? has_a_bachelor_curriculum? # === does_this_include_a_bachelor_curriculum?
2645
+
2646
+ # ========================================================================= #
2647
+ # === has_a_master_curriculum?
2648
+ #
2649
+ # This method will return true if the given Array has any master
2650
+ # curriculum; and it will return false otherwise.
2651
+ #
2652
+ # Note that there is an alias called
2653
+ # "is_this_lecture_registered_in_a_master_curriculum?". The name is a
2654
+ # of a misnomer, since the input to this method should be an Array
2655
+ # containing the IDs of the Curricula for which that lecture is
2656
+ # registered. This may be subject for change one day, but for
2657
+ # now (Sep 2018) we will keep it that way.
2658
+ # ========================================================================= #
2659
+ def has_a_master_curriculum?(array)
2660
+ Studium.has_a_master_curriculum?(array)
2661
+ end; alias is_a_master_curriculum? has_a_master_curriculum? # === is_a_master_curriculum?
2662
+ alias has_a_master_lecture? has_a_master_curriculum? # === has_a_master_lecture?
2663
+ alias has_a_master_curriculum_entry? has_a_master_curriculum? # === has_a_master_curriculum_entry?
2664
+ alias is_this_lecture_registered_in_a_master_curriculum? has_a_master_curriculum? # === is_this_lecture_registered_in_a_master_curriculum?
2665
+ alias does_this_include_a_master_curriculum? has_a_master_curriculum? # === does_this_include_a_master_curriculum?
2666
+
2667
+ # ========================================================================= #
2668
+ # === return_file_for_this_curriculum
2669
+ #
2670
+ # This method is a wrapper over the toplevel-method called
2671
+ # Studium.return_file_for_this_curriculum().
2672
+ # ========================================================================= #
2673
+ def return_file_for_this_curriculum(
2674
+ i = :bachelor_basisblock_biologie
2675
+ )
2676
+ if i.is_a? Array
2677
+ i.map {|line|
2678
+ return_file_for_this_curriculum(line)
2679
+ }
2680
+ else
2681
+ # ===================================================================== #
2682
+ #
2683
+ # bl $RUBY_STUDIUM/constants/return_file_for_this_curriculum.rb
2684
+ #
2685
+ # ===================================================================== #
2686
+ Studium.return_file_for_this_curriculum(i)
2687
+ end
2688
+ end; alias return_curriculum_file_based_on_this_input return_file_for_this_curriculum # === return_curriculum_file_based_on_this_input
2689
+ alias curriculum_location_of return_file_for_this_curriculum # === curriculum_location_of
2690
+ alias return_path_of_this_curriculum return_file_for_this_curriculum # === return_path_of_this_curriculum
2691
+ alias return_path_to_the_curriculum_file return_file_for_this_curriculum # === return_path_to_the_curriculum_file
2692
+ alias return_file_associated_with_this_curriculum return_file_for_this_curriculum # === return_file_associated_with_this_curriculum
2693
+ alias location_of_this_curriculum_file? return_file_for_this_curriculum # === location_of_this_curriculum_file?
2694
+
2695
+ # ========================================================================= #
2696
+ # === obtain_lectures_from_this_curriculum
2697
+ #
2698
+ # This method should be used whenever you wish to obtain all lectures
2699
+ # that belong to a specific curriculum, without any comments.
2700
+ #
2701
+ # An Array will be returned by this method.
2702
+ # ========================================================================= #
2703
+ def obtain_lectures_from_this_curriculum(
2704
+ i = :default,
2705
+ do_flatten_the_result = true
2706
+ )
2707
+ Studium.read_dataset_from_a_curriculum_file(i, :remove_comments, do_flatten_the_result).map {|entry|
2708
+ entry.squeeze(' ') # ← We don't want multiple ' ' in succession here.
2709
+ }
2710
+ end; alias return_lectures_from_this_curriculum obtain_lectures_from_this_curriculum # === return_lectures_from_this_curriculum
2711
+ alias return_lectures_of_this_curriculum obtain_lectures_from_this_curriculum # === return_lectures_of_this_curriculum
2712
+ alias return_lectures_from_this_curriculu obtain_lectures_from_this_curriculum # === return_lectures_from_this_curriculu
2713
+ alias return_lectures_from_this_curriculum_file obtain_lectures_from_this_curriculum # === return_lectures_from_this_curriculum_file
2714
+
2715
+ # ========================================================================= #
2716
+ # === fetch_this_curriculum
2717
+ #
2718
+ # This method can be used to specifically read in a registered local
2719
+ # curriculum.
2720
+ # ========================================================================= #
2721
+ def fetch_this_curriculum(i, &block)
2722
+ path = map_input_to_this_curriculum_filename(i)
2723
+ _ = readlines_with_proper_encoding(path, &block)
2724
+ if _
2725
+ return _.reject {|line|
2726
+ line.strip.empty? or line.strip.start_with?('#')
2727
+ }.map {|entry|
2728
+ entry.strip!
2729
+ entry.squeeze!(' ')
2730
+ if entry.include?('#')
2731
+ entry = entry.split('#').first.to_s
2732
+ end
2733
+ entry.strip
2734
+ }
2735
+ else
2736
+ false
2737
+ end
2738
+ end
2739
+
2740
+ # ========================================================================= #
2741
+ # === return_title_from_this_curriculum_file
2742
+ #
2743
+ # The first argument to this method should be the abbreviation of
2744
+ # that particular curriculum.
2745
+ #
2746
+ # Note that an Array can also be given as input to this method; this
2747
+ # may be done if a curriculum consists of more than one block.
2748
+ #
2749
+ # Usage example:
2750
+ #
2751
+ # return_title_from_this_curriculum_file(:indi2)
2752
+ #
2753
+ # ========================================================================= #
2754
+ def return_title_from_this_curriculum_file(
2755
+ i,
2756
+ use_a_shorter_name = false
2757
+ )
2758
+ Studium.return_title_from_this_curriculum_file(i, use_a_shorter_name)
2759
+ end; alias return_title_of return_title_from_this_curriculum_file # === return_title_of
2760
+ alias return_pretty_title_of_this_curriculum return_title_from_this_curriculum_file # === return_pretty_title_of_this_curriculum
2761
+ alias return_title_of_this_curriculum return_title_from_this_curriculum_file # === return_title_of_this_curriculum
2762
+
2763
+ require 'studium/toplevel_methods/map_input_to_this_curriculum_filename.rb'
2764
+ # ========================================================================= #
2765
+ # === map_input_to_this_curriculum_filename
2766
+ # ========================================================================= #
2767
+ def map_input_to_this_curriculum_filename(i)
2768
+ ::Studium.map_input_to_this_curriculum_filename(i)
2769
+ end
2770
+
2771
+ # ========================================================================= #
2772
+ # === chmod
2773
+ #
2774
+ # The second argument can also be an Array.
2775
+ # ========================================================================= #
2776
+ def chmod(
2777
+ new_mode = 0644, which_file = 'LINKS.md'
2778
+ )
2779
+ FileUtils.chmod(new_mode, which_file)
2780
+ end
2781
+
2782
+ # ========================================================================= #
2783
+ # === filter_for_all_passed_exams
2784
+ # ========================================================================= #
2785
+ def filter_for_all_passed_exams(i)
2786
+ return i.select {|a, b|
2787
+ b[:already_solved] and
2788
+ (b[:already_solved] == true)
2789
+ }
2790
+ end
2791
+
2792
+ # ========================================================================= #
2793
+ # === etomato
2794
+ # ========================================================================= #
2795
+ def etomato(i)
2796
+ e tomato(i)
2797
+ end
2798
+
2799
+ # ========================================================================= #
2800
+ # === is_a_master_lecture?
2801
+ # ========================================================================= #
2802
+ def is_a_master_lecture?(i)
2803
+ Studium.is_a_master_lecture?(i)
2804
+ end
2805
+
2806
+ # ========================================================================= #
2807
+ # === readlines_from_this_input_file
2808
+ #
2809
+ # This method is essentially File.readlines(), but we also use the
2810
+ # :encoding symbol to denote which Encoding to use.
2811
+ #
2812
+ # As first argument pass in the file path to the target input file.
2813
+ #
2814
+ # You should ideally use this method in a unified way, that is, whenever
2815
+ # you want to read the content of a file make use of this method here.
2816
+ # This makes it easier to have the functionality all in one place.
2817
+ #
2818
+ # Keep in mind that the file in question has to exist locally; the
2819
+ # file here will NOT check whether the given input file exists.
2820
+ # ========================================================================= #
2821
+ def readlines_from_this_input_file(
2822
+ this_file,
2823
+ use_this_encoding = :default_encoding,
2824
+ &block
2825
+ )
2826
+ yielded = nil
2827
+ if block_given?
2828
+ yielded = yield
2829
+ end
2830
+ case use_this_encoding
2831
+ # ======================================================================= #
2832
+ # === :default
2833
+ #
2834
+ # This refers to the default encoding, which is usually UTF-8 (Unicode).
2835
+ # ======================================================================= #
2836
+ when :default,
2837
+ :default_encoding
2838
+ use_this_encoding = ::Studium.main_encoding?
2839
+ end
2840
+ if use_this_encoding.is_a? Hash
2841
+ # ===================================================================== #
2842
+ # === :encoding
2843
+ # ===================================================================== #
2844
+ if use_this_encoding.has_key? :encoding
2845
+ use_this_encoding = use_this_encoding[:encoding]
2846
+ end
2847
+ end
2848
+ if this_file
2849
+ if this_file.is_a? Array
2850
+ return this_file.map {|inner_entry|
2851
+ if File.exist?(inner_entry)
2852
+ inner_entry = File.readlines(inner_entry, encoding: use_this_encoding)
2853
+ end
2854
+ inner_entry
2855
+ }.flatten
2856
+ elsif File.exist?(this_file)
2857
+ return File.readlines(
2858
+ this_file,
2859
+ encoding: use_this_encoding
2860
+ )
2861
+ end
2862
+ else
2863
+ unless yielded == :be_quiet
2864
+ e "Can not read in the file at #{this_file} as it does not exist."
2865
+ end
2866
+ return false
2867
+ end
2868
+ end; alias readlines_via_default_encoding readlines_from_this_input_file # === readlines_via_default_encoding
2869
+ alias readlines_with_default_encoding readlines_from_this_input_file # === readlines_with_default_encoding
2870
+ alias readlines_with_the_default_encoding readlines_from_this_input_file # === readlines_with_the_default_encoding
2871
+ alias file_readlines_of_this_file readlines_from_this_input_file # === file_readlines_of_this_file
2872
+ alias file_readlines readlines_from_this_input_file # === file_readlines
2873
+ alias readlines_with_proper_encoding readlines_from_this_input_file # === readlines_with_proper_encoding
2874
+ alias proper_readlines readlines_from_this_input_file # === proper_readlines
2875
+ alias default_readlines readlines_from_this_input_file # === default_readlines
2876
+ alias readlines readlines_from_this_input_file # === readlines
2877
+ # alias readlines_with_iso_encoding readlines_from_this_input_file # === readlines_with_iso_encoding
2878
+
2879
+ # ========================================================================= #
2880
+ # === open_in_browser
2881
+ # ========================================================================= #
2882
+ def open_in_browser(i)
2883
+ try_to_require_the_open_gem unless Object.const_defined?(:Open)
2884
+ Open.in_browser(i)
2885
+ end
2886
+
2887
+ # ========================================================================= #
2888
+ # === try_to_require_the_open_gem
2889
+ # ========================================================================= #
2890
+ def try_to_require_the_open_gem
2891
+ begin
2892
+ require 'open'
2893
+ rescue LoadError; end
2894
+ end
2895
+
2896
+ # ========================================================================= #
2897
+ # === silently_open_in_browser
2898
+ # ========================================================================= #
2899
+ def silently_open_in_browser(into)
2900
+ try_to_require_the_open_gem unless Object.const_defined?(:Open)
2901
+ Open.in_browser(into) { :be_silent }
2902
+ end
2903
+
2904
+ # ========================================================================= #
2905
+ # === roebe_path_to_file_lecture_information?
2906
+ # ========================================================================= #
2907
+ def roebe_path_to_file_lecture_information?
2908
+ '/home/x/programming/ruby/src/studium/lib/studium/yaml/lecture_information/'\
2909
+ 'lecture_information.yml'
2910
+ end
2911
+
2912
+ # ========================================================================= #
2913
+ # === does_this_line_include_a_german_weekday?
2914
+ # ========================================================================= #
2915
+ def does_this_line_include_a_german_weekday?(i)
2916
+ ARRAY_GERMAN_WEEKDAYS.any? {|this_german_weekday|
2917
+ i.include? this_german_weekday
2918
+ }
2919
+ end
2920
+
2921
+ # ========================================================================= #
2922
+ # === does_this_line_include_an_english_weekday?
2923
+ # ========================================================================= #
2924
+ def does_this_line_include_an_english_weekday?(i)
2925
+ ARRAY_ENGLISH_WEEKDAYS.any? {|this_english_weekday|
2926
+ i.include? this_english_weekday
2927
+ }
2928
+ end
2929
+
2930
+ # ========================================================================= #
2931
+ # === english_to_german_weekday
2932
+ #
2933
+ # This method will simply convert e. g. "Monday" into "Montag". In other
2934
+ # words: it will convert from the english name for a day into the
2935
+ # german name of that day.
2936
+ # ========================================================================= #
2937
+ def english_to_german_weekday(english_day)
2938
+ ENGLISH_TO_GERMAN_WEEKDAYS[english_day]
2939
+ end; alias english_to_german english_to_german_weekday # === english_to_german
2940
+
2941
+ # ========================================================================= #
2942
+ # === does_this_line_start_with_a_german_weekday?
2943
+ # ========================================================================= #
2944
+ def does_this_line_start_with_a_german_weekday?(i)
2945
+ result = false
2946
+ if i.include?(' ')
2947
+ i = i.dup
2948
+ if i.start_with?(' - "')
2949
+ i[0, 4] = ''
2950
+ end
2951
+ splitted = i.split(' ')
2952
+ first = splitted.first
2953
+ if is_german_weekday?(first)
2954
+ result = true
2955
+ end
2956
+ end
2957
+ return result
2958
+ end
2959
+
2960
+ # ========================================================================= #
2961
+ # === is_german_weekday?
2962
+ # ========================================================================= #
2963
+ def is_german_weekday?(i)
2964
+ ARRAY_GERMAN_WEEKDAYS.include?(i)
2965
+ end
2966
+
2967
+ # ========================================================================= #
2968
+ # === add_proper_year_entry_to_this_line
2969
+ #
2970
+ # This method will add a proper year entry to a line. It will either
2971
+ # append a year entry - or, which may be more useful, try to insert
2972
+ # the year-entry into a position that fits. The latter will make
2973
+ # use of a regex.
2974
+ #
2975
+ # A test string for the latter is the following:
2976
+ #
2977
+ # "Dienstag 02.10. 11:30-13:00 UZA2 Hörsaal 5 Raum 2Z202 2.OG"
2978
+ #
2979
+ # ========================================================================= #
2980
+ def add_proper_year_entry_to_this_line(line)
2981
+ result = line.dup
2982
+ current_year = Time.now.year
2983
+ use_this_regex = # See: https://rubular.com/r/xV0yNSYhWW
2984
+ /^(.+)(\d{2}\.\d{1,2}\.) (\d{1,2}:\d{1,2}(-| )?\d{1,2}:\d{1,2})(.+)$/
2985
+ if result =~ use_this_regex
2986
+ result.sub!(use_this_regex, '\1\2'+current_year.to_s+', \3\5')
2987
+ else # this here is the simpler case
2988
+ result << current_year # This is the variant that will simply append.
2989
+ end
2990
+ result
2991
+ end
2992
+
2993
+ # ========================================================================= #
2994
+ # === parse_this_line_for_date_entry
2995
+ # ========================================================================= #
2996
+ def parse_this_line_for_date_entry(i)
2997
+ use_this_regex = /\d{2}\.\d{2}\.\d{4}/ # See: https://rubular.com/r/ePRbty9Cjo49xv
2998
+ result = i.scan(use_this_regex).flatten
2999
+ result = result.first if result.is_a? Array
3000
+ return result
3001
+ end
3002
+
3003
+ # ========================================================================= #
3004
+ # === german_weekend_for?
3005
+ # ========================================================================= #
3006
+ def german_weekend_for?(
3007
+ i = '22.11.2022'
3008
+ )
3009
+ return Roebe.return_german_weekday(i)
3010
+ end
3011
+
3012
+ # ========================================================================= #
3013
+ # === file_passed_exams_per_month
3014
+ # ========================================================================= #
3015
+ def file_passed_exams_per_month
3016
+ Studium.file_passed_exams_per_month
3017
+ end; alias passed_exams_per_month file_passed_exams_per_month # === passed_exams_per_month
3018
+ alias local_csv_file? file_passed_exams_per_month # === local_csv_file?
3019
+
3020
+ # ========================================================================= #
3021
+ # === ensure_that_a_base_directory_exists_for_this_file
3022
+ #
3023
+ # This method expects a file path, such as "/tmp/foo/bar.html".
3024
+ #
3025
+ # If such a file path is passed to this method then this
3026
+ # method will try to ensure that /tmp/foo/ exists (the directory).
3027
+ # ========================================================================= #
3028
+ def ensure_that_a_base_directory_exists_for_this_file(i)
3029
+ _ = File.dirname(i)
3030
+ unless File.directory?(_)
3031
+ FileUtils.mkdir_p(_)
3032
+ end
3033
+ end
3034
+
3035
+ end; end
3036
+
3037
+ if __FILE__ == $PROGRAM_NAME
3038
+ require 'verbose_truth'
3039
+ alias e puts
3040
+ x = Studium::Base.new
3041
+ # x.current_semester? # This will be :winter or :summer.
3042
+ e x.this_month_has_n_days?('10')
3043
+ e x.this_month_has_n_days?('11')
3044
+ e x.this_month_has_n_days?('12')
3045
+ e 'Do we have konsole support? '+
3046
+ VerboseTruth[
3047
+ x.konsole_support?.to_s
3048
+ ]
3049
+ p x.web_liner
3050
+ Studium::Base.new.directory_to_the_exam_topics?
3051
+ p base.weekday?
3052
+ p base.today?
3053
+ p base.select_lectures_with_this_key(:exam_registration_at)
3054
+ end