diff --git a/DataAnalyser.py b/DataAnalyser.py
index c03b8c8ba89db122273d6fab01075b7d5cc84474..641614522dd13d78c9e9ba49ed07dc7f60e65be2 100644
--- a/DataAnalyser.py
+++ b/DataAnalyser.py
@@ -1,7 +1,8 @@
 import math
-from typing import List
-
+import numpy as numpy
+import pandas as pandas
 from fastf1.core import Session, Lap, Laps
+from pandas.errors import IndexingError
 
 from DataHandler import DataHandler
 
@@ -12,14 +13,14 @@ class DataAnalyser(DataHandler):
 
     # ===== Overtakes =====
 
-    def analyseRacesForOvertakes(self, races: List[Session]):
-        overtakesInRaces: List[List[int]] = [[]]
+    def analyseRacesForOvertakes(self, races: list[Session]):
+        overtakesInRaces: list[list[int]] = [[]]
         for race in races:
             overtakesInRaces.append(self.analyseRaceForOvertakes(race))
         return overtakesInRaces
 
     def analyseRaceForOvertakes(self, race: Session):
-        overtakesInLaps: List[int] = self.countOvertakesPerLap(race)
+        overtakesInLaps: list[int] = self.countOvertakesPerLap(race)
         return overtakesInLaps
 
     def countOvertakesPerLap(self, race: Session):
@@ -39,18 +40,16 @@ class DataAnalyser(DataHandler):
         of laps the race had), all laps in the list will be either None objects or empty Panda Dataframes.
         '''
 
-        # TODO: Implement returning starting grid for lapNumber = 1
-        # TODO: Sidestep getting start position from lap, get from session results instead, for lap 1 SOL (start of lap)
-
-
-
         previousLaps: Laps = race.laps.pick_laps(lapNumber - 1)
         currentLaps: Laps = race.laps.pick_laps(lapNumber)
         out: int = self.numberOfDrivers  # weighting for drivers that did not complete the lap (they are "out" of the lap/race)
         weightedOrder: list[(Lap, int)] = [(None, out)] * 20  # data from start of lap + weighting for end of lap; initialize to add laps in lap's starting order
 
+        if self.activateDebugOvertakeAnalysis: print(f"Lap: {lapNumber}")
+
         # Put every driver's laps in a sortable array & apply weighting based on position at end of lap
         for driver in race.drivers:
+            if self.activateDebugOvertakeAnalysis: print(f"Driver: {driver}")
             driversPreviousLap: Laps = previousLaps.pick_drivers(
                 driver)  # should only get 1 lap, but data type shenanigans
             driversCurrentLap: Laps = currentLaps.pick_drivers(driver)
@@ -64,10 +63,12 @@ class DataAnalyser(DataHandler):
                 endPosition = int(driversCurrentLap['Position'].iloc[0])
 
             except ValueError:
-                if self.activateDebugOvertakeAnalysis: print(f"Could not fetch positions from lap; driver %d likely didn't finish lap %d or %d",
-                      driver, lapNumber, (lapNumber + 1))
+                if self.activateDebugOvertakeAnalysis:
+                    print(f"Could not fetch positions from lap; driver %d likely didn't finish lap %d or %d",
+                          driver, lapNumber, (lapNumber + 1))
             except IndexError:
-                if self.activateDebugOvertakeAnalysis: print("['Position'].iloc[0] was out of bounds; lap was likely empty because driver previously left the race")
+                if self.activateDebugOvertakeAnalysis:
+                    print("['Position'].iloc[0] was out of bounds; lap was likely empty because driver previously left the race")
 
             weightedOrder[startPosition - 1] = (driversCurrentLap, endPosition)
 
@@ -97,16 +98,19 @@ class DataAnalyser(DataHandler):
 
         return overtakes
 
-    def isAnInLap(self, lap: Lap):
-        # TODO: Implement :)
-        return False
-
-
     def getGridPositionFor(self, driverNumber: int, race: Session):
         sessionResults = race.results
         gridPosition: int = int(sessionResults['GridPosition'].loc[driverNumber])
         return gridPosition
 
+    def isAnInLap(self, lap: Lap):
+        try:
+            return not pandas.isnull(lap['PitInTime'].iloc[0])
+        except: # caused when lap is empty and possibly when lap is None
+            return True # like in-laps, empty laps should not be counted for overtakes
+
+
+
 
     def getGridPositions(self, race: Session):
         sessionResults = race.results
@@ -127,7 +131,7 @@ class DataAnalyser(DataHandler):
         return gridPositions
 
     def getRunningLapsPositions(self, race: Session):
-        runningLapsPositions: List[dict[str, int]] = []
+        runningLapsPositions: list[dict[str, int]] = []
         allRaceLaps = race.laps
 
         for raceLapIndex in range(race.total_laps):
@@ -163,8 +167,8 @@ class DataAnalyser(DataHandler):
 
     # ===== Weather =====
 
-    def analyseRacesForWeather(self, races: List[Session]):
-        weatherInRaces: List[List[bool]] = [[]] # isRaining per lap per race
+    def analyseRacesForWeather(self, races: list[Session]):
+        weatherInRaces: list[list[bool]] = [[]] # isRaining per lap per race
         for race in races:
             weatherInRace = self.analyseRaceForWeather(race)
             weatherInRaces.append(weatherInRace)
@@ -176,8 +180,8 @@ class DataAnalyser(DataHandler):
 
     # ===== Tire Changes =====
 
-    def getEarliestTireChanges(self, races: List[Session]):
-        earliestTireChanges: List[int] = [[]]  # isRaining per lap per race
+    def getEarliestTireChanges(self, races: list[Session]):
+        earliestTireChanges: list[int] = [[]]  # isRaining per lap per race
         for race in races:
             earliestTireChange = self.getEarliestTireChange(race)
             earliestTireChanges.append(earliestTireChange)
@@ -186,15 +190,15 @@ class DataAnalyser(DataHandler):
     # Returns -1 if no tire change occured
     def getEarliestTireChange(self, race: Session):
         earliestTireChangeLap: int = -1
-        compoundsPerLap: List[List[str]] = self.getCompoundsForRace(race)
+        compoundsPerLap: list[list[str]] = self.getCompoundsForRace(race)
         compoundsPerLap[0] = compoundsPerLap[1] # presume grid tires same as 1st lap; races are only picked if weather change after first 10 laps anyways, so its ok
         startingCompound: str = self.getPredominantCompound(compoundsPerLap[0])
         earliestTireChangeLap = self.getFirstLapWithOppositeCompound(compoundsPerLap, startingCompound)
 
         return earliestTireChangeLap
 
-    def getLatestTireChanges(self, races: List[Session]):
-        latestTireChanges: List[int] = [[]]  # isRaining per lap per race
+    def getLatestTireChanges(self, races: list[Session]):
+        latestTireChanges: list[int] = [[]]  # isRaining per lap per race
         for race in races:
             latestTireChange = self.getLatestTireChange(race)
             latestTireChanges.append(latestTireChange)
@@ -203,14 +207,14 @@ class DataAnalyser(DataHandler):
     # Returns -1 if no tire change occured
     def getLatestTireChange(self, race: Session):
         latestTireChangeLap: int = -1
-        compoundsPerLap: List[List[str]] = self.getCompoundsForRace(race)
+        compoundsPerLap: list[list[str]] = self.getCompoundsForRace(race)
         compoundsPerLap[0] = compoundsPerLap[1]  # presume grid tires same as 1st lap; races are only picked if weather change after first 10 laps anyways, so its ok
         startingCompound: str = self.getPredominantCompound(compoundsPerLap[0])
         latestTireChangeLap = self.getFirstLapWithoutCompound(compoundsPerLap, startingCompound)
 
         return latestTireChangeLap
 
-    def getFirstLapWithoutCompound(self, compoundsPerLap: List[List[str]], startingCompound: str):
+    def getFirstLapWithoutCompound(self, compoundsPerLap: list[list[str]], startingCompound: str):
         currentLap = 0
         filter = self.setFilter(startingCompound)
         for compoundsThisLap in compoundsPerLap:
@@ -224,16 +228,15 @@ class DataAnalyser(DataHandler):
         return -1 # no lap without compound found; all laps use same compound type
 
     def getCompoundsForRace(self, race: Session):
-        compoundsPerLap: List[List[str]] = [[]]
+        compoundsPerLap: list[list[str]] = [[]]
         allRaceLaps = race.laps
 
         for raceLapIndex in range(race.total_laps):
-            compoundsThisLap: List[str] = []
+            compoundsThisLap: list[str] = []
             for driver in race.drivers:
                 raceLap = allRaceLaps.pick_laps(raceLapIndex + 1)  # Lap 0 doesn't exist
                 raceLap = raceLap.pick_drivers(driver)
                 try:
-                    driverAbbreviation = raceLap['Driver'].iloc[0]
                     compound = raceLap['Compound'].iloc[0]
                     compoundsThisLap.append(compound)
                 except:  # triggered when not all drivers that took part reached lap, probably by crashing or being behind
@@ -242,7 +245,7 @@ class DataAnalyser(DataHandler):
 
         return compoundsPerLap
 
-    def getPredominantCompound(self, compoundsThisLap: List[str]):
+    def getPredominantCompound(self, compoundsThisLap: list[str]):
         slickCounter = 0
         interCounter = 0
         wetCounter = 0
@@ -256,7 +259,7 @@ class DataAnalyser(DataHandler):
         if wetCounter == mostUsed: return 'WET'
         return 'error'
 
-    def getFirstLapWithOppositeCompound(self, compoundsPerLap: List[List[str]], startingCompound: str):
+    def getFirstLapWithOppositeCompound(self, compoundsPerLap: list[list[str]], startingCompound: str):
         filter = self.setFilter(startingCompound)
         currentLap = 0
         for compoundsThisLap in compoundsPerLap:
diff --git a/DataChecker.py b/DataChecker.py
index 6ddbfa08f76dab291b67b1c8eca0b9e3e4684c81..9b9da549c98f9d3aeee8d54dd98aeb6e79bbd63e 100644
--- a/DataChecker.py
+++ b/DataChecker.py
@@ -3,6 +3,7 @@ from DataHandler import DataHandler
 
 class DataChecker(DataHandler):
 
+    @DeprecationWarning
     def check_imported_race(self, race_data):
         for current_lap in range(len(race_data)):
             print(f"Lap {current_lap}")
@@ -14,6 +15,7 @@ class DataChecker(DataHandler):
             print()
         print(f"Number of laps run: {len(race_data) - 1}")
 
+    @DeprecationWarning
     def check_imported_races(self, races):
         for race in races:
             self.check_imported_race(race)
\ No newline at end of file
diff --git a/DataImporter.py b/DataImporter.py
index 40e7e2b44008f79233ffeabed9e1a7fef865bafe..b2dc7f54e5fd7cb8ee886757fef71f0c434c897d 100644
--- a/DataImporter.py
+++ b/DataImporter.py
@@ -1,10 +1,5 @@
-import json
-import time
-
 import fastf1
-import requests
 from abc import ABC
-from typing import List
 
 from fastf1.core import Session
 
@@ -17,7 +12,7 @@ from DataHandler import DataHandler
 class DataImporter(DataHandler, ABC):
 
     def importRaceSessions(self, races):
-        sessions: List[Session] = []
+        sessions: list[Session] = []
         for race in races:
             sessions.append(self.importRaceSession(race))
         return sessions
diff --git a/DataPlotter.py b/DataPlotter.py
index 19bf93c625474f96a03dd502378c5260b11ad13c..9b95e74a803499825f3852f095be2e9022b6d95f 100644
--- a/DataPlotter.py
+++ b/DataPlotter.py
@@ -1,18 +1,10 @@
-import math
-from abc import ABC
-from typing import List
-
 import matplotlib.pyplot as plt
 import numpy as np
-
-
-from fastf1.core import Session, Lap
-
 from DataHandler import DataHandler
 
 
 class DataPlotter(DataHandler):
-    def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: List[int], earliestTireChange: int, latestTireChange: int, raceName: str):
+    def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: list[int], earliestTireChange: int, latestTireChange: int, raceName: str):
 
         overtakesPerLap.insert(0, 0) # Insert 0th lap, which cannot have overtakes
         laps: int = len(overtakesPerLap)
diff --git a/README.md b/README.md
index 08fdf44bcce089974b2bdcfb3ee5032ea3268342..bc6e6d871154e4f8f6ab08065a1a4232ea955e5e 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@ On some READMEs, you may see small images that convey metadata, such as whether
 Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
 
 ## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
 
 ## Usage
 Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
diff --git a/Todos.md b/Todos.md
index edd108378cb02553aa49d1e46d8ccf3a1d5727f4..65c2d807e4fd00acf6879cf7bedeac669102fd45 100644
--- a/Todos.md
+++ b/Todos.md
@@ -1,11 +1,11 @@
 # Todo (sorted by priority)
 - Fetch rain races via API, not Reddit
-- Adjust for pitstop discrepancies
+- Adjust for position changes caused by crashes (keep out of calculation similarly to PCs due to pitstops ?)
 - Include safety car periods & driver crashes
 - Automatically determine if race is DWR or SWR
 - Adjust for situations like Canada 2024 -> 2 drivers taking wets at the start does not constitute a weather change
   - Implement actual 1/2 of drivers changing compounds rule
-- Save data in CSV file
+- Cache data in CSV file for faster access / analysis
 - Adjust for finding multiple weather changes in a race, not just one
 - Read out number of drivers participating in session, rather than hardcoding number of drivers (since it might change from 20 to more (or less) in future)
 - Also read out direct weather data from API
@@ -17,4 +17,6 @@
 # Done
 - Automatically title graph by race name (no more hardcoding the graph name)
 - Migrate counting of overtakes functionality from integer-array based to list\[(Lap, int)] based so that in-laps 
-  can be accounted for
\ No newline at end of file
+  can be accounted for
+- Count overtakes in 1st lap after migration
+- Adjust for pitstop discrepancies
diff --git a/main.py b/main.py
index a74cedabdaaad05459f7ef12fe1d413099c8110a..53850a43076729aa0597e9ad9c3468aa973f34ee 100644
--- a/main.py
+++ b/main.py
@@ -1,19 +1,9 @@
-from typing import List
-
-import matplotlib.pyplot as plt
-
-import fastf1.plotting
-
-
 from DataAnalyser import DataAnalyser
 from DataChecker import DataChecker
 from DataImporter import DataImporter
 from DataPlotter import DataPlotter
 
 
-
-
-
 class Main:
 
     def main(self):
@@ -40,7 +30,7 @@ class Main:
 
 
             # Analyse
-            overtakesInRaces: List[int] = analyser.analyseRaceForOvertakes(raceSession)
+            overtakesInRaces: list[int] = analyser.analyseRaceForOvertakes(raceSession)
             print("Overtake analysis done")
             # weatherInRaces = analyser.analyseRaceForWeather(raceSession)
             earliestTireChange: int = analyser.getEarliestTireChange(raceSession) # first lap where someone switched from slicks to non slicks or vice versa, denoted by lap number