     ; adjust rowspan of <th>
     (attr $thElem "rowspan" (max nrNonEmptyRows 2))))
 
-(defn- create-lesson-div
-  "Creates a <div> element for a new lesson using jQuery"
-  [& {:keys [moduleCode moduleName lessonType lessonGroup venue slotsOcc
-             bgColorCssClass isActuallySelected?]}]
-  (let [$divElem  ($ "<div />" (js-obj "class" "lesson"))]
-    (.addClass $divElem bgColorCssClass)
-    ; add background color css class
-    (.append $divElem (text ($ "<p />") (str moduleCode " " moduleName)))
-    (.append $divElem (text ($ "<p />") (str lessonType " [" lessonGroup "]")))
-    (.append $divElem (text ($ "<p />") venue))
-    (width $divElem (str (* half-hour-pixels slotsOcc) "px"))
-    ; make the <div> less opaque for a lesson added by jQuery UI draggable
-    (if (not isActuallySelected?)
-        (.addClass $divElem "lesson-droppable-not-hover"))
-    $divElem))
-
-(defn- add-module-lesson!
-  "Adds a single lesson of a module the timetable.
-   Returns a `ModulesSelectedLessonInfo` object augmented with the `:divElem`,
-   `:moduleCode`, `:lessonType` and `:lessonGroup` keys."
-  [& {:keys [moduleCode moduleName lessonType lessonGroup
-             day startTime endTime venue
-             bgColorCssClass isActuallySelected?]}]
-  (let [rowNum    (find-free-row-for-lesson day startTime endTime)
-        slotsOcc  (- endTime startTime)
-
-        $divElem
-        (create-lesson-div :moduleCode moduleCode, :moduleName moduleName,
-                           :lessonType lessonType, :lessonGroup lessonGroup,
-                           :venue venue, :slotsOcc slotsOcc,
-                           :bgColorCssClass bgColorCssClass,
-                           :isActuallySelected? isActuallySelected?)]
-    ; Create new row if necessary
-    (if (= rowNum (timetable-day-get-nr-rows day))
-        (add-new-row-to-timetable-day! day))
-
-    ; Update in-memory representation of timetable
-    (timetable-add-lesson! day
-                           rowNum
-                           {:moduleCode moduleCode,
-                            :lessonType lessonType,
-                            :lessonGroup lessonGroup,
-                            :startTime startTime,
-                            :endTime endTime}
-                           $divElem)
-
-    (let [$td (html-timetable-get-td day rowNum startTime)]
-      (.append $td $divElem)
-      ; Increase colspan and delete the <td> after it that occupy the timeslot
-      ; of the lesson
-      (attr $td "colspan" slotsOcc)
-      (doseq [$siblingTd (take (- slotsOcc 1) (.nextAll $td))]
-        (.remove $siblingTd))
-
-      {:day day, :rowNum rowNum, :startTime startTime, :endTime endTime,
-       :moduleCode moduleCode, :lessonType lessonType, :lessonGroup lessonGroup,
-       :divElem $divElem})))
-
-(def ^{:doc     "Sequence of `TimetableLessonInfo` objects augmented with the
-                 `:divElem`, `:moduleCode`, `:lessonType`, `:lessonGroup` keys.
-                 These are 'fake' lessons created when a selected lesson is
-                 being dragged by the user, in order for him/her to switch to
-                 a different lesson group for that lesson type."
-       :private true}
-  Lessons-Created-By-Draggable nil)
-
-; Forward declaration
-(declare add-module-lesson-group!)
-(declare overall-timetable-prune-empty-rows)
-(declare add-missing-td-elements-replacing-lesson)
-(declare remove-lesson-group-html)
-(declare shift-lessons-upwards-to-replace-empty-slots!)
-(declare update-ModulesSelected-for-affected-days)
-
-(def ^{:doc     "Key for a data attribute added to a draggable <div> helper
-                 when the helper has been dropped onto a droppable <div>.
-                 This is used to detect if a lesson group switch has occurred."
-       :private true}
-  LESSON-GROUP-CHANGE-KEY "lessonGroupChangeTo")
-
-(defn- lesson-draggable-start-evt-handler-maker
-  "Returns a function that can be used as the `start` event handler for a
-   draggable lesson.
-
-   Details of the returned function can be found here:
-
-       http://api.jqueryui.com/draggable/#event-start"
-  [moduleCode lessonType selectedLessonGroup bgColorCssClass]
-  (fn [evt ui]
-    (.addClass (aget ui "helper") "lesson-draggable-helper")
-    (.css (aget ui "helper") "cursor" "grabbing")
-    (let [allLessonGroups
-          (get-all-lesson-group-strings moduleCode lessonType)
-
-          notSelectedLessonGroups
-          (remove #{selectedLessonGroup} allLessonGroups)
-
-          ; Add all the <div> elements
-          augmentedTTLessonInfoSeq
-          (doall
-            (flatten
-              (map (fn [unselectedLessonGroup]
-                     (add-module-lesson-group! moduleCode lessonType
-                                               unselectedLessonGroup
-                                               bgColorCssClass false))
-                   notSelectedLessonGroups)))]
-      (set! Lessons-Created-By-Draggable augmentedTTLessonInfoSeq))))
-
-(defn- $lesson-div-remove
-  "Removes the <div> object of a lesson module, and replaces the former
-   columns occupied by its parent <td> with new <td> elements."
-  [$lessonDiv startTime endTime]
-  (let [$parentTd (parent $lessonDiv)]
-    (remove-attr $parentTd "colspan")
-    (.remove $lessonDiv)
-    (add-missing-td-elements-replacing-lesson $parentTd startTime endTime)))
-
-(defn- lesson-draggable-stop-evt-handler-maker
-  "Returns a function used as the `stop` event handler for a draggable lesson."
-  [moduleCode lessonType lessonGroup bgColorCssClass]
-  (fn [evt ui]
-    (let [$helper         (aget ui "helper")
-          destLessonGroup (data $helper LESSON-GROUP-CHANGE-KEY)
-
-          affectedDaysSet
-          (get-set-from-seq-of-maps-with-day-key Lessons-Created-By-Draggable)]
-
-      (doseq [augTTLessonInfo Lessons-Created-By-Draggable]
-        (timetable-remove-lesson! (:day augTTLessonInfo)
-                                  (:rowNum augTTLessonInfo)
-                                  (dissoc augTTLessonInfo :divElem :day
-                                          :rowNum)))
-
-      (doseq [augTTLessonInfo Lessons-Created-By-Draggable]
-        (let [$divElem  (:divElem augTTLessonInfo)]
-          ($lesson-div-remove $divElem (:startTime augTTLessonInfo)
-                              (:endTime augTTLessonInfo))))
-
-      (overall-timetable-prune-empty-rows affectedDaysSet)
-      (set! Lessons-Created-By-Draggable nil)
-
-      ; User has dropped the draggable helper <div> onto a droppable
-      (if (not (nil? destLessonGroup))
-          (let [augTTLessonInfoSeq (remove-lesson-group-html moduleCode
-                                                             lessonType)
-                affectedDaysSet    (get-set-from-seq-of-maps-with-day-key
-                                     augTTLessonInfoSeq)]
-            ; remove the current lesson group
-            (doseq [augTTLessonInfo augTTLessonInfoSeq]
-              (let [day          (:day augTTLessonInfo)
-                    rowNum       (:rowNum augTTLessonInfo)
-                    ttLessonInfo (dissoc augTTLessonInfo :day :rowNum)]
-                (timetable-remove-lesson! day rowNum ttLessonInfo)))
-
-            (shift-lessons-upwards-to-replace-empty-slots! augTTLessonInfoSeq)
-            (overall-timetable-prune-empty-rows affectedDaysSet)
-            (update-ModulesSelected-for-affected-days affectedDaysSet)
-
-            ; add the newly selected lesson group
-            (add-module-lesson-group! moduleCode lessonType destLessonGroup
-                                      bgColorCssClass true)
-
-            (update-document-location-hash-with-changed-lesson-group!
-              moduleCode lessonType destLessonGroup))))))
-
-(defn- make-added-lessons-draggable
-  "Makes the <div> elements of selected lessons draggable."
-  [$divElemSeq moduleCode lessonType lessonGroup bgColorCssClass]
-  ; And Drag event handler
-  (doseq [$divElem $divElemSeq]
-    (.css $divElem "cursor" "grab")
-    (.draggable $divElem
-                (js-obj "zIndex" 100
-                        "helper" "clone"
-                        "revert" "invalid"
-                        "start"  (lesson-draggable-start-evt-handler-maker
-                                   moduleCode lessonType lessonGroup
-                                   bgColorCssClass)
-                        "stop"   (lesson-draggable-stop-evt-handler-maker
-                                   moduleCode lessonType lessonGroup
-                                   bgColorCssClass)))))
-
-(defn- make-fake-lessons-droppable
-  "For 'fake' lessons created due to a lesson <div> being dragged, we make
-   them droppable in order for the user to switch lesson groups."
-  [augModuleSelectedLessonInfoSeq]
-  (doseq [augModuleSelectedLessonInfo augModuleSelectedLessonInfoSeq]
-    (let [$divElem (:divElem augModuleSelectedLessonInfo)]
-      (.droppable
-        $divElem
-        (js-obj "tolerance" "intersect"
-
-                "over"
-                (fn [evt ui]
-                  (.removeClass $divElem "lesson-droppable-not-hover")
-                  (.addClass $divElem "lesson-droppable-hover"))
-
-                "out"
-                (fn [evt ui]
-                  (.removeClass $divElem "lesson-droppable-hover")
-                  (.addClass $divElem "lesson-droppable-not-hover"))
-
-                "drop"
-                (fn [evt ui]
-                  (let [$helper (aget ui "helper")]
-                    ; Set a data attribute on the draggable helper to signal
-                    ; that the user has dropped the <div> on a droppable to
-                    ; change the lesson group
-                    (data $helper
-                          LESSON-GROUP-CHANGE-KEY
-                          (:lessonGroup augModuleSelectedLessonInfo)))))))))
-
-(defn- add-module-lesson-group!
-  "Adds a lesson group of a module to the timetable.
-
-   The `isActuallySelected?` param is used to indicate if the current lesson
-   group is selected by the user.
-   A value of `true` indicates that the user actually selected the lesson group.
-   A value of `false` indicates that the current lesson group is added by the
-   `lesson-draggable-start-evt-handler-maker` function and is not selected by
-   the user.
-
-   Returns a sequence of `ModulesSelectedLessonInfo` objects each augmented
-   with the `:divElem`, `:moduleCode`, `:lessonType`, `:lessonGroup` keys."
-  [moduleCode lessonType lessonGroup bgColorCssClass isActuallySelected?
-   & {:keys [addedViaUrlHashInit?] :or {addedViaUrlHashInit? false}}]
-  (if (module-has-lesson-group? moduleCode lessonType lessonGroup)
-      (let [moduleName          (get-module-name-from-module-code moduleCode)
-            modulesMapLessonSeq (get-ModulesMapLesson-seq moduleCode lessonType
-                                                          lessonGroup)
-
-            augLessonInfoSeq
-            (doall
-              (map (fn [modulesMapLesson]
-                     (add-module-lesson!
-                       :moduleCode moduleCode, :moduleName moduleName,
-                       :lessonType lessonType, :lessonGroup lessonGroup,
-                       :day        (:day modulesMapLesson),
-                       :startTime  (:startTime modulesMapLesson),
-                       :endTime    (:endTime modulesMapLesson),
-                       :venue      (:venue modulesMapLesson),
-                       :bgColorCssClass bgColorCssClass,
-                       :isActuallySelected? isActuallySelected?))
-                   modulesMapLessonSeq))
-
-            lessonInfoSeq       (map #(dissoc %1 :divElem :moduleCode
-                                              :lessonType :lessonGroup)
-                                     augLessonInfoSeq)
-            $divElemSeq         (map #(:divElem %1) augLessonInfoSeq)]
-        (if isActuallySelected?
-            (do
-              (update-ModulesSelected-with-lesson-group! moduleCode lessonType
-                                                         lessonGroup
-                                                         lessonInfoSeq)
-              (if (module-not-in-ModulesSelectedOrder? moduleCode)
-                  (do
-                    (add-to-ModulesSelectedOrder! moduleCode)
-                    ; Micro optimization for modules added via url hash
-                    ; during initialization
-                    (if (not addedViaUrlHashInit?)
-                        (select2-box-update-modules))))
-
-              ; Only lesson types with more than 1 option of lesson group
-              ; will be draggable
-              (if (module-lesson-type-has-multiple-choices? moduleCode
-                                                            lessonType)
-                  (make-added-lessons-draggable $divElemSeq moduleCode
-                                                lessonType lessonGroup
-                                                bgColorCssClass)))
-
-            ; lesson was added due to draggable <div>
-            ; Make it droppable
-            (make-fake-lessons-droppable augLessonInfoSeq))
-        augLessonInfoSeq)))
-
-(defn add-module!
-  "Adds a module to the timetable.
-
-   A random lesson group of each type of lesson (Lecture, Tutorial, etc) will
-   be added."
-  [moduleCode]
-  (if (not (is-module-selected? moduleCode))
-      (let [lessonTypes     (get-all-lesson-types-for-module moduleCode)
-            bgColorCssClass (get-next-lesson-bg-color-css-class)
-
-            newModInfoSeq
-            (reduce (fn [moduleInfoSeq lessonType]
-                      (conj moduleInfoSeq
-                            {:moduleCode  moduleCode,
-                             :lessonType  lessonType,
-                             :lessonGroup
-                             (get-first-lesson-group-for-module-lesson-type
-                               moduleCode lessonType)}))
-                    []
-                    lessonTypes)]
-
-        (doseq [moduleInfo newModInfoSeq]
-          (add-module-lesson-group! (:moduleCode moduleInfo)
-                                    (:lessonType moduleInfo)
-                                    (:lessonGroup moduleInfo)
-                                    bgColorCssClass
-                                    true))
-
-        ; Update URL hash with newly added module
-        (update-document-location-hash-with-new-module!
-          {:moduleCode moduleCode,
-
-           :preToUrlHashLessonGroupSeqSorted
-           (sort-PreToUrlHashLessonGroup-seq
-             (map #(dissoc
-                     (assoc %1 :lessonType
-                            (Lesson-Type-Long-To-Short-Form (:lessonType %1)))
-                     :moduleCode)
-                  newModInfoSeq))}))))
-
-(defn- get-module-info-from-url-hash-module-info
-  "Computes the final module info sequence for modules added via the url hash
-   on page initialization.
-
-   NOTE: This function should only be called by
-         `add-module-lesson-groups-from-url-hash!`"
-  [moduleInfoSeq]
-  (let [moduleLessonGroupsMap
-        (reduce (fn [lgMap modInfo]
-                  ; Replaces earlier lesson groups with later ones if we
-                  ; encounter a duplicate lesson type
-                  (assoc-in lgMap [(:moduleCode modInfo) (:lessonType modInfo)]
-                            (:lessonGroup modInfo)))
-                {}
-                moduleInfoSeq)
-
-        moduleCodesSeq (distinct (map #(:moduleCode %1) moduleInfoSeq))
-
-        ; Map of Module Code -> Sequence of lesson type strings
-        moduleLessonTypes
-        (reduce (fn [lessonTypesMap moduleCode]
-                  (let [ltMap (get moduleLessonGroupsMap moduleCode)]
-                    (assoc lessonTypesMap moduleCode (keys ltMap))))
-                {}
-                moduleCodesSeq)
-
-        ; Similar to `moduleLessonTypes`, but contains the full sequence of
-        ; lesson type strings
-        moduleLessonTypesFull
-        (reduce (fn [lessonTypesMap moduleCode]
-                  (assoc lessonTypesMap moduleCode
-                         (get-all-lesson-types-for-module moduleCode)))
-                {}
-                moduleCodesSeq)
-
-        ; Obtained from the difference between `moduleLessonTypesFull` and
-        ; `moduleLessonTypes`
-        missingModuleLessonTypes
-        (reduce (fn [missingLessonTypesMap moduleCode]
-                  (let [missingLessonTypes
-                        (clojure.set/difference
-                          (set (get moduleLessonTypesFull moduleCode))
-                          (set (get moduleLessonTypes moduleCode)))]
-                    (if (empty? missingLessonTypes)
-                        missingLessonTypesMap
-                        (assoc missingLessonTypesMap moduleCode
-                               (seq missingLessonTypes)))))
-                {}
-                moduleCodesSeq)
-
-        ; similar to `moduleLessonGroupsMap`, but includes missing lesson types
-        moduleLessonGroupsMapFinal
-        (reduce (fn [lgMapFinal [moduleCode missingLessonTypes]]
-                  (reduce
-                    (fn [lgMap lessonType]
-                      (assoc-in lgMap [moduleCode lessonType]
-                                (get-first-lesson-group-for-module-lesson-type
-                                  moduleCode lessonType)))
-                    lgMapFinal
-                    missingLessonTypes))
-                moduleLessonGroupsMap
-                missingModuleLessonTypes)]
-
-    ; Produce the final module info sequence
-    (flatten
-      (map (fn [moduleCode]
-             (map (fn [[lessonType lessonGroup]]
-                    {:moduleCode  moduleCode
-                     :lessonType  lessonType
-                     :lessonGroup lessonGroup})
-                  (get moduleLessonGroupsMapFinal moduleCode)))
-           moduleCodesSeq))))
-
-(defn add-module-lesson-groups-from-url-hash!
-  "Adds the module lesson groups available in the url hash. Erroneous lesson
-   groups are ignored. If there are missing lesson groups for any module after
-   going through the url hash, a random lesson group is chosen.
-
-   NOTE: This function should only be called once."
-  [urlHash]
-  (let [moduleUrlHashArray                (.split urlHash "&")
-
-        modUrlHashRegex
-        #"^([A-Z]+\d{4}[A-Z]*)_(DL|L|LAB|PL|PT|R|SEM|ST|T|T2|T3)=([A-Z0-9]+)$"
-
-        ; Sequence of non-nil match arrays
-        matchArraySeq
-        (filter (fn [matchArray] (not (nil? matchArray)))
-                (map (fn [modUrlHash] (.exec modUrlHashRegex modUrlHash))
-                     moduleUrlHashArray))
-
-        ; Sequence of existing lesson groups
-        moduleInfoExistent
-        (filter
-          #(module-has-lesson-group? (:moduleCode %1) (:lessonType %1)
-                                     (:lessonGroup %1))
-          ; convert matchArrays to maps
-          (map (fn [matchArray]
-                 {:moduleCode  (nth matchArray 1)
-                  :lessonType  (Lesson-Type-Short-To-Long-Form
-                                 (nth matchArray 2))
-                  :lessonGroup (nth matchArray 3)})
-               matchArraySeq))
-
-        ; Module code to CSS class for lesson div background color
-        moduleToColorsMap
-        (reduce
-          (fn [m2cMap moduleCode]
-            (assoc m2cMap moduleCode (get-next-lesson-bg-color-css-class)))
-          {}
-          (distinct (map (fn [modInfo] (:moduleCode modInfo))
-                         moduleInfoExistent)))
-
-        moduleInfoFinal
-        (get-module-info-from-url-hash-module-info moduleInfoExistent)]
-
-    (.log js/console (str "moduleInfoExistent = " (.stringify js/JSON (clj->js moduleInfoExistent))))
-    (.log js/console (str "moduleInfoFinal = " (.stringify js/JSON (clj->js moduleInfoFinal))))
-    ; Add the module lesson groups
-    (doseq [modInfo moduleInfoFinal]
-      (let [moduleCode      (:moduleCode modInfo)
-            bgColorCssClass (get moduleToColorsMap moduleCode)]
-        (add-module-lesson-group! moduleCode
-                                  (:lessonType modInfo)
-                                  (:lessonGroup modInfo)
-                                  bgColorCssClass
-                                  true
-                                  :addedViaUrlHashInit? true)))
-
-    ; Update Select2 box, since this is not done in `add-module-lesson-group!`.
-    ; Repeated work will be done there if we did so
-    (select2-box-update-modules)
-    ; Update url hash
-    (set-document-location-hash-based-on-modules-order!)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Functions for Removing Modules
-;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defn- add-missing-td-elements-replacing-lesson
-  "Adds <td> elements that were removed by the `add-module-lesson!` function
-   to make way for the lesson."
-  [$parentTd startTime endTime]
-  (loop [$currentTd $parentTd
-         timeIdx    (inc startTime)]
-    (if (>= timeIdx endTime)
-        nil
-        (let [[hourClass minuteClass]
-              (get-css-hour-minute-classes-for-time timeIdx)
-
-              $newTdElem
-              ($ "<td />" (js-obj "class" (str hourClass " " minuteClass)))]
-          ; Insert after new <td> after the current <td>
-          (insert-after $newTdElem $currentTd)
-          ; Then use the new <td> as the current <td> in the next iteration
-          (recur $newTdElem (inc timeIdx))))))
-
-(defn- remove-lesson-group-html
-  "Removes a lesson group for a module from the HTML timetable.
-   This does NOT remove any empty rows / perform module shifting.
-
-   Returns a sequence of `ttLessonInfo` objects which contain
-   additional `:day` and `:rowNum` keys."
-  [moduleCode lessonType]
-  (let [lessonGroupDetails (get-in ModulesSelected [moduleCode lessonType])
-        lessonGroup        (:label lessonGroupDetails)
-        lessonInfoSeq      (:info lessonGroupDetails)]
-    (map (fn [modSelLessonInfo]
-           (let [day          (:day modSelLessonInfo)
-                 rowNum       (:rowNum modSelLessonInfo)
-                 startTime    (:startTime modSelLessonInfo)
-                 endTime      (:endTime modSelLessonInfo)
-                 ttLessonInfo {:moduleCode moduleCode, :lessonType lessonType,
-                               :lessonGroup lessonGroup, :startTime startTime,
-                               :endTime endTime}
-                 $lessonDiv   (timetable-get-lesson-div day rowNum
-                                                        ttLessonInfo)]
-             ($lesson-div-remove $lessonDiv startTime endTime)
-             (assoc ttLessonInfo :day day, :rowNum rowNum)))
-         lessonInfoSeq)))
-
-(defn- get-largest-consecutive-time-slot-freed-up-by-lesson
-  "Given a removed lesson, find the largest interval on the same row which is
-   freed up due to the its removal.
-
-   For instance, given this timetable row:
-
-   x | x | x |  |  |  | y | y | y | y |  |  | z | z
-
-   And we remove the lesson occupying the slots labelled 'y'. The 4 slots
-   currently occupied by 'y', along with the 3 empty slots to its left and the
-   2 empty slots to its right will be freed up.
-
-   Given that the first slot occupied by the label 'x' is the index 0, this
-   function will return the vector [3 11].
-
-   The parameter `removedAugTTLessonInfo` is a `TimetableLessonInfo` object
-   augmented with the `:day` and `:rowNum` keys."
-  [removedAugTTLessonInfo]
-  (let [day        (:day removedAugTTLessonInfo)
-        rowNum     (:rowNum removedAugTTLessonInfo)
-        startTime  (:startTime removedAugTTLessonInfo)
-        endTime    (:endTime removedAugTTLessonInfo)
-        minTimeIdx time-helper/TIME-INDEX-MIN
-        maxTimeIdx time-helper/TIME-INDEX-MAX]
-
-    (.log js/console "get-largest-consecutive-time-slot-freed-up-by-lesson")
-    [
-      ; Find the lesson right before the removed lesson
-      (let [immediateTTLessonInfoBefore
-            (timetable-get-closest-TimetableLessonInfo-before-time
-              day rowNum startTime)]
-        (if (nil? immediateTTLessonInfoBefore)
-            minTimeIdx
-            (:endTime immediateTTLessonInfoBefore)))
-
-      ; Find the lesson right after the removed lesson
-      (let [immediateTTLessonInfoAfter
-            (timetable-get-closest-TimetableLessonInfo-on-or-after-time
-              day rowNum endTime)]
-        (if (nil? immediateTTLessonInfoAfter)
-            maxTimeIdx
-            (dec (:startTime immediateTTLessonInfoAfter))))
-    ]))
-
-(defn- find-replacement-lessons-within-time
-  "For a removed lesson, find other lessons on the same day but in a row below
-   the removed lesson which could be shifted upwards and take the timeslots
-   freed up by the removed lesson.
-
-   The `removedAugTTLessonInfo` parameter is an `TimetableLessonInfo` object
-   augmented with the `:day` and `:rowNum` keys.
-
-   Returns a map, where keys are `TimetableLessonInfo` objects augmented with
-   `:day` and `:rowNum` keys, and values are jQuery <div> objects for the
-   shifted lesson."
-  [{:keys [day rowNum startTime endTime] :as removedAugTTLessonInfo}]
-  (let [; This is the time range freed up by removal of the lesson
-        [lowTimeIdx highTimeIdx]
-        (get-largest-consecutive-time-slot-freed-up-by-lesson
-          removedAugTTLessonInfo)
-
-        not-occupied?
-        (fn [occupiedVec startTime endTime]
-          (.log js/console (str "inside not-occupied?, occupiedVec = " (.stringify js/JSON (clj->js occupiedVec))))
-          (every? #(nil? %1)
-                  (map #(nth occupiedVec %1)
-                       (range startTime endTime))))]
-
-    (.log js/console "find-replacement-lessons-within-time")
-    (.log js/console (str "lowTimeIdx = " lowTimeIdx ", highTimeIdx = " highTimeIdx))
-    (:augTTLessonInfoMapToShift
-      (reduce
-        (fn [{:keys [augTTLessonInfoMapToShift occupiedVec]
-              :as   reduceResult}
-             rowIdx]
-          (if (timetable-row-empty? day rowIdx)
-              ; Skip empty row
-              reduceResult
-
-              ; Non-empty row
-              (let [ttLessonInfoToShift
-                    (timetable-row-get-lessons-satisfying-pred
-                      day rowIdx
-                      (fn [{:keys [startTime endTime]}]
-                        (and (>= startTime lowTimeIdx)
-                             (<= (dec endTime) highTimeIdx)
-                             (not-occupied? occupiedVec startTime endTime))))]
-                (.log js/console "suspect above")
-                (.log js/console (str "rowIdx = " rowIdx))
-                (.log js/console (str "occupiedVec = " (.stringify js/JSON (clj->js occupiedVec))))
-                {:augTTLessonInfoMapToShift
-                 (reduce (fn [augTTLessonInfoMap [ttLessonInfo $divElem]]
-                           (.log js/console ":augTTLessonInfoMapToShift")
-                           (assoc augTTLessonInfoMap
-                                  (assoc ttLessonInfo :day day :rowNum rowIdx)
-                                  $divElem))
-                         augTTLessonInfoMapToShift
-                         ttLessonInfoToShift)
-
-                 :occupiedVec
-                 (reduce (fn [occVec [{:keys [startTime endTime]}  _]]
-                           (.log js/console ":occupiedVec")
-                           (reduce (fn [ov timeIdx] (assoc ov timeIdx true))
-                                   occVec
-                                   (range startTime endTime)))
-                         occupiedVec
-                         ttLessonInfoToShift)})))
-        {:augTTLessonInfoMapToShift {},
-         ; nil = free slot, true = occupied slot
-         :occupiedVec      (vec (map (fn [t] nil)
-                                     (range time-helper/TIME-INDEX-MIN
-                                            (inc time-helper/TIME-INDEX-MAX))))}
-        ; go through each row in the day, below the current row
-        (drop (inc rowNum) (range (timetable-day-get-nr-rows day)))))))
-
-(defn- shift-lesson-to-row!
-  "Shifts a lesson from its original row up to the given row.
-
-   The parameter `augTTLessonInfo` is a `TimetableLessonInfo` object augmented
-   with the `:day` and `:rowNum` keys."
-  [destinationRowNum {:keys [day rowNum startTime endTime] :as augTTLessonInfo}
-   $divElem]
-  (let [slotsOccupied (- endTime startTime)
-        $sourceTd     (html-timetable-get-td day rowNum startTime)
-        $destTd       (html-timetable-get-td day destinationRowNum startTime)
-        ttLessonInfo  (dissoc augTTLessonInfo :day :rowNum)]
-    (.log js/console (str "day = " day ", sourceRowNum = " rowNum ", destinationRowNum = " destinationRowNum))
-    ; Transfer lesson <div> to the destination <td>
-    (.append $destTd $divElem)
-    ; restore the colspan of the source <td>
-    (remove-attr $sourceTd "colspan")
-    ; fill in removed <td> for the source <td>
-    (add-missing-td-elements-replacing-lesson $sourceTd startTime endTime)
-    ; remove sibling <td> for the destination <td> to make way for columns
-    ; occupied by $divElem
-    (doseq [$siblingTd (take (dec slotsOccupied) (.nextAll $destTd))]
-      (.remove $siblingTd))
-    ; update colspan of destination <td>
-    (attr $destTd "colspan" slotsOccupied)
-    ; update `Timetable` global
-    (timetable-remove-lesson! day rowNum ttLessonInfo)
-    (timetable-add-lesson! day destinationRowNum ttLessonInfo $divElem)))
-
-(defn- shift-lessons-upwards-to-replace-empty-slots!
-  "For each removed lesson, see if there are any lessons in rows below it that
-   can be shifted upwards to occupy the empty slots resulting from its removal.
-
-   The parameter `removedAugmentedTTLessonInfoSeq` is a sequence of
-   `TimetableLessonInfo` objects augmented with the `:day` and `:rowNum` keys."
-  [removedAugmentedTTLessonInfoSeq]
-  (let [; we do not consider any lessons on empty rows for ease of
-        ; implementation
-        exclude-lessons-on-empty-rows
-        (fn [lessonInfoSeq]
-          (filter (fn [{:keys [day rowNum]}]
-                    (timetable-row-not-empty? day rowNum))
-                  lessonInfoSeq))
-
-        sort-lesson-info-seq
-        (fn [lessonInfoSeq]
-          (sort #(let [dayA (:day %1)
-                       dayB (:day %2)]
-                   (if (= dayA dayB)
-                       (< (:rowNum %1) (:rowNum %2))
-                       (< dayA dayB)))
-                lessonInfoSeq))]
-
-    (.log js/console "Hoo hoo")
-    (loop [sortedAugTTLessonInfoSeq
-           (sort-lesson-info-seq (exclude-lessons-on-empty-rows
-                                   removedAugmentedTTLessonInfoSeq))
-
-           nextLessonInfoVec    []]
-      (.log js/console "Inside the loop, the loop")
-      (cond (and (empty? sortedAugTTLessonInfoSeq) (empty? nextLessonInfoVec))
-            nil
-
-            ; we're done for the current set of lessons. Move on to the
-            ; set of lessons that were shifted upwards.
-            (empty? sortedAugTTLessonInfoSeq)
-            (recur (sort-lesson-info-seq (exclude-lessons-on-empty-rows
-                                           nextLessonInfoVec))
-                   [])
-
-            ; find timeslot to shift up to replace gap
-            :else
-            (let [currentAugTTLessonInfo (first sortedAugTTLessonInfoSeq)
-                  rowNum                 (:rowNum currentAugTTLessonInfo)
-
-                  ; map of augmented `TimeTableLessonInfo` objects to the
-                  ; jQuery <div> element
-                  augTTLessonInfoTo$DivElem
-                  (find-replacement-lessons-within-time currentAugTTLessonInfo)]
-
-              (doseq [[augTTLessonInfo $divElem] augTTLessonInfoTo$DivElem]
-                (.log js/console "shift-lesson-to-row")
-                (shift-lesson-to-row! rowNum augTTLessonInfo $divElem))
-              (.log js/console "gonna recur...")
-              (recur (rest sortedAugTTLessonInfoSeq)
-                     ; append newly shifted lessons to nextLessonInfoVec
-                     (reduce (fn [augTTLessonInfoVec [augTTLessonInfo _]]
-                               (conj augTTLessonInfoVec augTTLessonInfo))
-                             nextLessonInfoVec
-                             augTTLessonInfoTo$DivElem)))))))
-
-(defn- overall-timetable-prune-empty-rows
-  "Removes empty rows resulting from the removal of lessons on given days."
-  [affectedDaysSet]
-  (doseq [day affectedDaysSet]
-    (let [rowsPartition (timetable-day-get-empty-and-non-empty-rows day)]
-      (.log js/console (str "day = " day ", emptyRows = "
-                            (.stringify js/JSON (clj->js (:emptyRows rowsPartition)))
-                            ", nonEmptyRows = "
-                            (.stringify js/JSON (clj->js (:nonEmptyRows rowsPartition)))))
-
-      (timetable-prune-empty-rows-for-day! day rowsPartition)
-      (html-timetable-prune-empty-rows-for-day day rowsPartition))))
-
-(defn- update-ModulesSelected-for-affected-days
+(defn- update-ModulesSelected-for-affected-days!
   "Given a set of days that may possibly be affected by removal and shifting of
    lessons, update the individual entries in the `ModulesSelected` global."
   [affectedDaysSet]

                         :startTime startTime,
                         :endTime endTime}))))))))))

(defn remove-module!
  "Removes a module from the timetable.


        (.log js/console "Whats up")

        ; Update `ModulesSelected`
        (update-ModulesSelected-for-affected-days! affectedDaysSet)
        (.log js/console "Boo ya!")
        (.log js/console (str "ModulesSelected:" (.stringify js/JSON (clj->js ModulesSelected))))

