{ "cells": [ { "attachments": { }, "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "
\n", "

\n", " Modeling Flight Delays\n", "

\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "

The Question

\n", "\n", "What is the best way to increase the number of flights without delays? We will model airplane traffic between several airports and test two different modeling strategies to avoid flight delays and maintain flight turnaround efficiency." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "# Configure Jupyter so figures appear in the notebook\n", "%matplotlib inline\n", "\n", "# Configure Jupyter to display the assigned value after an assignment\n", "%config InteractiveShell.ast_node_interactivity='last_expr_or_assign'\n", "\n", "# import functions from the modsim library\n", "from modsim import *\n", "\n", "# set the random number generator\n", "np.random.seed(7)\n", "import random\n", "\n", "import pandas as pd\n", "import datetime\n", "from dateutil.parser import parse\n", "import math\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Below is data collected in 2008 which details flights and delays. This data was narrowed to include only Delta (DL) and United (UA) flights between airports LAX, JFK, ATL, IAD, SEA. By using only flights between specific airports, we reduce the likelihood that the data is influenced primarily by the airport or the airline." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearMonthDayofMonthDayOfWeekDepTimeArrTimeUniqueCarrierActualElapsedTimeAirTimeArrDelay...OriginDestDistanceTaxiInTaxiOutCarrierDelayWeatherDelayNASDelaySecurityDelayLateAircraftDelay
02008112613.01407.0UA294.0278.0-24.0...LAXJFK24753.013.0NaNNaNNaNNaNNaN
12008123615.01435.0UA320.0298.04.0...LAXJFK24753.019.0NaNNaNNaNNaNNaN
22008134607.01454.0UA347.0299.023.0...LAXJFK24758.040.00.00.023.00.00.0
32008145618.01523.0UA365.0284.052.0...LAXJFK24753.078.00.00.052.00.00.0
42008156615.01416.0UA301.0282.0-15.0...LAXJFK24754.015.0NaNNaNNaNNaNNaN
..................................................................
10152200822952128.02311.0DL103.077.0-2.0...ATLIAD5338.018.0NaNNaNNaNNaNNaN
10153200822951858.02041.0DL103.079.00.0...ATLIAD5337.017.0NaNNaNNaNNaNNaN
10154200822951455.01646.0DL111.078.05.0...ATLIAD5335.028.0NaNNaNNaNNaNNaN
1015520082295824.01002.0DL98.078.0-5.0...ATLIAD5334.016.0NaNNaNNaNNaNNaN
1015620082295957.01147.0DL110.082.0-2.0...ATLIAD5337.021.0NaNNaNNaNNaNNaN
\n", "

10157 rows × 21 columns

\n", "
" ], "text/plain": [ " Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier \\\n", "0 2008 1 1 2 613.0 1407.0 UA \n", "1 2008 1 2 3 615.0 1435.0 UA \n", "2 2008 1 3 4 607.0 1454.0 UA \n", "3 2008 1 4 5 618.0 1523.0 UA \n", "4 2008 1 5 6 615.0 1416.0 UA \n", "... ... ... ... ... ... ... ... \n", "10152 2008 2 29 5 2128.0 2311.0 DL \n", "10153 2008 2 29 5 1858.0 2041.0 DL \n", "10154 2008 2 29 5 1455.0 1646.0 DL \n", "10155 2008 2 29 5 824.0 1002.0 DL \n", "10156 2008 2 29 5 957.0 1147.0 DL \n", "\n", " ActualElapsedTime AirTime ArrDelay ... Origin Dest Distance \\\n", "0 294.0 278.0 -24.0 ... LAX JFK 2475 \n", "1 320.0 298.0 4.0 ... LAX JFK 2475 \n", "2 347.0 299.0 23.0 ... LAX JFK 2475 \n", "3 365.0 284.0 52.0 ... LAX JFK 2475 \n", "4 301.0 282.0 -15.0 ... LAX JFK 2475 \n", "... ... ... ... ... ... ... ... \n", "10152 103.0 77.0 -2.0 ... ATL IAD 533 \n", "10153 103.0 79.0 0.0 ... ATL IAD 533 \n", "10154 111.0 78.0 5.0 ... ATL IAD 533 \n", "10155 98.0 78.0 -5.0 ... ATL IAD 533 \n", "10156 110.0 82.0 -2.0 ... ATL IAD 533 \n", "\n", " TaxiIn TaxiOut CarrierDelay WeatherDelay NASDelay SecurityDelay \\\n", "0 3.0 13.0 NaN NaN NaN NaN \n", "1 3.0 19.0 NaN NaN NaN NaN \n", "2 8.0 40.0 0.0 0.0 23.0 0.0 \n", "3 3.0 78.0 0.0 0.0 52.0 0.0 \n", "4 4.0 15.0 NaN NaN NaN NaN \n", "... ... ... ... ... ... ... \n", "10152 8.0 18.0 NaN NaN NaN NaN \n", "10153 7.0 17.0 NaN NaN NaN NaN \n", "10154 5.0 28.0 NaN NaN NaN NaN \n", "10155 4.0 16.0 NaN NaN NaN NaN \n", "10156 7.0 21.0 NaN NaN NaN NaN \n", "\n", " LateAircraftDelay \n", "0 NaN \n", "1 NaN \n", "2 0.0 \n", "3 0.0 \n", "4 NaN \n", "... ... \n", "10152 NaN \n", "10153 NaN \n", "10154 NaN \n", "10155 NaN \n", "10156 NaN \n", "\n", "[10157 rows x 21 columns]" ] }, "execution_count": 3, "metadata": { }, "output_type": "execute_result" } ], "source": [ "trips = pd.read_csv('2008.csv')" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "

The Model

\n", "\n", "To model flights and delays, we will use a state object which keeps a list of planes and also keeps track of ticks with the time variable. These variables are global but change throughout, so putting them in the state object makes sense. To simulate the planes themselves, a Plane class is created, which contains any variables for the planes and several functions to update them. \n", "\n", "Our model, obviously, is more simple than a real-life airport system. We have limited our traffic to only a few airports, and a small number of planes. We have also decided to focus on airport delays--effectively ignoring in-flight delays due to weather, diversions, or other spontaneous circumstances." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
values
planes[]
time0
\n", "
" ], "text/plain": [ "planes []\n", "time 0\n", "dtype: object" ] }, "execution_count": 4, "metadata": { }, "output_type": "execute_result" } ], "source": [ "planes = []\n", "time = 0\n", "state = State(planes = planes,time = time)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "class Plane:\n", " \n", " def __init__(self, airline, inFlight, distance, target): ## Initializes an instance of the Plane class\n", " self.airline = airline\n", " self.inFlight = inFlight\n", " self.distance = distance\n", " self.target = target\n", " self.wait = 0\n", " self.data = []\n", " \n", " def move(self): ##the plane's movement tracker, which moves the plane towards its target by one unit every tick\n", " if self.distance > 0:\n", " self.data.append(str(self.distance))\n", " self.distance -= 1\n", " return True\n", " else:\n", " return False\n", " \n", " def delay(self): ##the plane's delay timer at airports, which counts down tick by one second if it is at an airport\n", " if self.wait > 0:\n", " self.data.append(0)\n", " self.wait -= 1\n", " return True\n", " else:\n", " return False\n", " \n", " def go_to(self, target): ##sets a new target airport for the plane, while also calculating the distance from its current location to the target\n", " temp = self.target\n", " self.target = target\n", " self.distance = flight_time(temp,target)\n", " \n", " ##--------Getters---------##\n", " def getAirline(self):\n", " return self.airline\n", " def getInFlight(self):\n", " return self.inFlight\n", " def getDistance(self):\n", " return self.distance\n", " def getTarget(self):\n", " return self.target\n", " def getData(self):\n", " return self.data\n", " def getWait(self):\n", " return self.wait\n", " \n", " ##--------Setters---------##\n", " def setAirline(self,airline):\n", " self.airline = airline\n", " def setInFlight(self,inFlight):\n", " self.inFlight = inFlight\n", " def setDistance(self,distance):\n", " self.distance = distance\n", " def setTarget(self,target):\n", " self.target = target\n", " def setWait(self, wait):\n", " self.wait = wait\n", " \n", "def flight_time(x, y): #Outside the plane class, flight time calculates the time/distance in ticks between any of the 5 airports in the simulation\n", " if (x == \"ATL\" and y == \"LAX\") or (y == \"ATL\" and x == \"LAX\"):\n", " return 51\n", " elif (x == \"ATL\" and y == \"IAD\") or (y == \"ATL\" and x == \"IAD\"):\n", " return 21\n", " elif (x == \"ATL\" and y == \"JFK\") or (y == \"ATL\" and x == \"JFK\"):\n", " return 28\n", " elif (x == \"ATL\" and y == \"SEA\") or (y == \"ATL\" and x == \"SEA\"):\n", " return 57\n", " elif (x == \"LAX\" and y == \"IAD\") or (y == \"LAX\" and x == \"IAD\"):\n", " return 59\n", " elif (x == \"LAX\" and y == \"SEA\") or (y == \"LAX\" and x == \"SEA\"):\n", " return 35\n", " elif (x == \"LAX\" and y == \"JFK\") or (y == \"LAX\" and x == \"JFK\"):\n", " return 66\n", " elif (x == \"IAD\" and y == \"JFK\") or (y == \"IAD\" and x == \"JFK\"):\n", " return 17\n", " elif (x == \"IAD\" and y == \"SEA\") or (y == \"IAD\" and x == \"SEA\"):\n", " return 70\n", " elif (x == \"JFK\" and y == \"SEA\") or (y == \"JFK\" and x == \"SEA\"):\n", " return 76\n", " else:\n", " return False\n", " \n", "def delay_factor(baseNum, margin): ##Adds an element of randomness to the delay, which can be adjusted with the base number and the amout it can deviate\n", " rnd = random.randint(1,margin*2)\n", " return int((baseNum - (margin)) + rnd)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ ], "source": [ "plane1 = Plane(\"UA\",False,0,\"LAX\")\n", "plane2 = Plane(\"DL\",False,0,\"ATL\")\n", "plane3 = Plane(\"UA\",False,0,\"LAX\")\n", "plane4 = Plane(\"DL\",False,0,\"ATL\")\n", "plane5 = Plane(\"UA\",False,0,\"LAX\")\n", "plane6 = Plane(\"DL\",False,0,\"ATL\")\n", "plane7 = Plane(\"UA\",False,0,\"LAX\")\n", "plane8 = Plane(\"DL\",False,0,\"LAX\")\n", "plane9 = Plane(\"UA\",False,0,\"ATL\")\n", "plane10 = Plane(\"DL\",False,0,\"LAX\")\n", "plane11 = Plane(\"UA\",False,0,\"ATL\")\n", "state.planes.append(plane1)\n", "state.planes.append(plane2)\n", "state.planes.append(plane3)\n", "state.planes.append(plane4)\n", "state.planes.append(plane5)\n", "state.planes.append(plane6)\n", "state.planes.append(plane7)\n", "state.planes.append(plane8)\n", "state.planes.append(plane9)\n", "state.planes.append(plane10)\n", "state.planes.append(plane11)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "For comparison we are using two different models for airlines, assuming each has only 2 planes, going between 2 airports. \n", "\n", "Delta Airlines (DL) will be using a model where 1 plane is kept in reserve. Any time delta experiences a significant delay (variable maxDelay), the reserve plane will be called in to replace the original, instantly resetting the delay to 0. \n", "\n", "United Airlines (UA) will be using a model where all planes are always in service, flying opposite directions between the 2 airports. Since there is no reserve plane, United makes turnarounds longer to maintain planes and reduce the impact of delays. However, if one of their planes exceeds a significant delay (variable maxDelay), the flight is cancelled, and the plane must wait until the next scheduled flight. Since the planes fly between two airports, this means two previously scheduled flights are cancelled.\n", "\n", "The data will be obtained in the form of a ratio, comparing the number of successful flights for each airline. The variables for maximum delays and turnarounds are designed to be as close to real life as possile based on research. Running the simulation usually takes upwards of 2 minutes because of the vast quantity of data being processed. We experimented with smaller time scales and numbers but this resulted in very varied outputs." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def run_simulation(numPlanes, air1,\n", " air2): # The run_simulation function runs the simulation\n", " state.time = 0\n", " DL = 0\n", " UA = 0\n", " planes = state.planes[0:((numPlanes * 2) - 1)]\n", " for x in range(100000):\n", " state.time += 1\n", " DL += sim1(planes, air1, air2, 22)\n", " UA += sim2(planes, air1, air2, 22, 5)\n", " return [DL, UA, DL / UA]\n", "\n", "\n", "def sim1(planes, air1, air2,\n", " maxDelay): # Sim1 implements Delta's reserve plane model\n", " success = 0\n", " for plane in planes:\n", " if plane.getAirline() == \"DL\":\n", " if not (plane.delay()):\n", " if plane.getWait() > maxDelay:\n", " plane.setWait(0)\n", " if not (plane.move()):\n", " success += 1\n", " if (plane.getTarget() == air1):\n", " plane.go_to(air2)\n", " else:\n", " plane.go_to(air1)\n", " plane.setWait(delay_factor(15, 9))\n", " return success\n", "\n", "\n", "def sim2(planes, air1, air2, maxDelay,\n", " addTurn): # Sim2 implements United's model\n", " success = 0 # that operates without reserve planes\n", " for plane in planes:\n", " if plane.getAirline() == \"UA\":\n", " if not (plane.delay()):\n", " if not (plane.move()):\n", " success += 1\n", " if (plane.getTarget() == air1):\n", " plane.go_to(air2)\n", " else:\n", " plane.go_to(air1)\n", " delay = delay_factor(15, 9)\n", " plane.setWait(delay + addTurn)\n", " if delay > maxDelay:\n", " success -= 2\n", " return success\n", "\n", "\n", "test1 = run_simulation(2, \"IAD\",\n", " \"JFK\") # This section collects data from run_simulation\n", "test2 = run_simulation(\n", " 2, \"ATL\", \"LAX\") # and creates lists to store all the different datasets\n", "test3 = run_simulation(2, \"JFK\", \"SEA\")\n", "test4 = run_simulation(3, \"IAD\", \"JFK\")\n", "test5 = run_simulation(3, \"ATL\", \"LAX\")\n", "test6 = run_simulation(3, \"JFK\", \"SEA\")\n", "test7 = run_simulation(4, \"IAD\", \"JFK\")\n", "test8 = run_simulation(4, \"ATL\", \"LAX\")\n", "test9 = run_simulation(4, \"JFK\", \"SEA\")\n", "test10 = run_simulation(5, \"IAD\", \"JFK\")\n", "test11 = run_simulation(5, \"ATL\", \"LAX\")\n", "test12 = run_simulation(5, \"JFK\", \"SEA\")\n", "test13 = run_simulation(6, \"IAD\", \"JFK\")\n", "test14 = run_simulation(6, \"ATL\", \"LAX\")\n", "test15 = run_simulation(6, \"JFK\", \"SEA\")\n", "\n", "tests = [\n", " test1, test2, test3, test4, test5, test6, test7, test8, test9, test10,\n", " test11, test12, test13, test14, test15\n", "]\n", "\n", "DL_Flights = []\n", "for test in tests:\n", " DL_Flights.append(test[0])\n", "\n", "UA_Flights = []\n", "for test in tests:\n", " UA_Flights.append(test[1])\n", "\n", "ratio = []\n", "for test in tests:\n", " ratio.append(test[2])\n", "\n", "num_planes = [2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6]\n", "flight_length = [1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5]" ] }, { "attachments": { }, "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "

\n", " The Results\n", "

\n", "The ratios of Delta's successful flights versus United's succesful flights are shown below. For each flight path, there are four ratios--each representing a test with a different number of planes. For reference, the flight paths are in order of shortest time to longest." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "print(ratio)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "9e741fe8f566d84cfe682cfa61584a78e52cd7e8", "text/plain": [ "
" ] }, "execution_count": 8, "metadata": { "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# Creates a bubble plot to plot the ratio of successful flights\n", "data = {'a': num_planes,\n", " 'c': \"blue\",\n", " 'd': (flight_length)}\n", "data['b'] = ratio\n", "data['d'] = np.abs(data['d']) * 15\n", "\n", "plt.scatter('a', 'b', c='c', s='d', data=data)\n", "plot([2, 6], [1, 1], color='purple', linestyle='-', linewidth=2)\n", "plt.xlabel('Number of Planes')\n", "plt.ylabel('Ratio of Successful Flights')\n", "plt.title('Plot 1: Ratios of Successful Flights v Number of Planes')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "This graph shows the ratio of successful flights from United to those of Delta. The higher the ratio, the more successful Delta is. The line at y = 1 represents the point at which Delta begins having more successful flights than United. The size of each bubble represents the length of the flight." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "b4b40ab03e7f2ae944964458758a8653ee4431f7", "text/plain": [ "
" ] }, "execution_count": 9, "metadata": { "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# Creates a bubble plot to plot the number of successful flights for each airline\n", "data = {'a': num_planes,\n", " 'c': \"maroon\",\n", " 'd': flight_length}\n", "data['b'] = DL_Flights\n", "data['d'] = np.abs(data['d']) * 20\n", "\n", "plt.scatter('a', 'b', c='c', s='d', data=data)\n", "\n", "data = {'a': num_planes,\n", " 'c': \"navy\",\n", " 'd': flight_length}\n", "data['b'] = UA_Flights\n", "data['d'] = np.abs(data['d']) * 20\n", "\n", "plt.scatter('a', 'b', c='c', s='d', data=data)\n", "\n", "plt.xlabel('Number of Planes')\n", "plt.ylabel('Number of Successful Flights')\n", "plt.title('Plot 2: Number of Successful Flights v Number of Planes')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "This graph shows the individual number of flights from United (blue) and Delta (red) that are successful. The size of each bubble represents the length of the flights." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "

\n", " The Interpretation\n", "

\n", "The data in these two plots shows most clearly that given a certain time period, more shorter flights can be completed than longer ones. This is no surprise, and more interesting is the ratios of United flights to Delta flights. With less planes, it is clear that United's model of using all of its planes works well, even if they have a slightly longer turnaround. However, as the airlines' fleets grow, Delta gains the advantage. This can best be explained by the fact that Delta constantly has 1 reserve plane, and so the ratio of reserve planes:in service planes decreases, while the advantage of having a reserve plane doesn't.\n", "\n", "Plot 1 shows the ratio increasing throughout (shifting towards Delta's side) but levelling off near the end. This could imply that Delta's strategy works better with more planes, but only up to a point, after which it is still beneficial, but stops improving relative to United.\n", "\n", "Plot 2 shows a very significant change in the number of successful short flights, and a smaller change in the longer flights. This can be attributed to the fact that there are more shorter flights so any imbalances will compound much faster. However, it should also be noted that Delta's method definitely seems more effective with shorter flights. This can be seen in both plots, as in plot 1, the shorter flights (smaller bubbles) have a much larger ratio, and in the second plot, delta's short flights exceed those of United earlier than the long flights.\n", "\n", "In conclusion, United's model tends to be better suited to longer flights and fewer planes, while the opposite is true for Delta. " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 0 }