From 6726a156b386d62eb308a3b3aae6b3cbbf46b906 Mon Sep 17 00:00:00 2001 From: JamesFlare1212 Date: Fri, 31 Jan 2025 13:20:17 -0500 Subject: [PATCH] add csci-1200-hw-2 --- README.md | 4 +- content/en/posts/csci-1100/hw-1/index.md | 4 +- content/en/posts/csci-1100/hw-2/index.md | 2 - .../hw-2/csci-1200-hw-2-flowchart-zh_cn.svg | 3 + content/en/posts/csci-1200/hw-2/index.md | 1299 +++++++++++++++++ .../en/posts/csci-1200/hw-2/ride_sharing.7z | Bin 0 -> 45049 bytes content/zh-cn/posts/csci-1100/hw-1/index.md | 2 - content/zh-cn/posts/csci-1100/hw-2/index.md | 2 - content/zh-cn/posts/csci-1200/hw-2/index.md | 834 ++++++++++- .../posts/csci-1200/hw-2/ride_sharing.7z | Bin 0 -> 45049 bytes 10 files changed, 2137 insertions(+), 13 deletions(-) create mode 100644 content/en/posts/csci-1200/hw-2/csci-1200-hw-2-flowchart-zh_cn.svg create mode 100644 content/en/posts/csci-1200/hw-2/index.md create mode 100644 content/en/posts/csci-1200/hw-2/ride_sharing.7z create mode 100644 content/zh-cn/posts/csci-1200/hw-2/ride_sharing.7z diff --git a/README.md b/README.md index 66cad85..146484a 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Then, install Hugo. For Linux: ```bash -wget https://github.com/gohugoio/hugo/releases/download/v0.136.5/hugo_extended_0.136.5_linux-amd64.deb -dpkg -i hugo_extended_0.136.5_linux-amd64.deb +wget https://github.com/gohugoio/hugo/releases/download/v0.141.0/hugo_extended_0.141.0_linux-amd64.deb +dpkg -i hugo_extended_0.141.0_linux-amd64.deb ``` For MacOS: diff --git a/content/en/posts/csci-1100/hw-1/index.md b/content/en/posts/csci-1100/hw-1/index.md index 63ec8b9..95a93bb 100644 --- a/content/en/posts/csci-1100/hw-1/index.md +++ b/content/en/posts/csci-1100/hw-1/index.md @@ -10,7 +10,7 @@ author: email: avatar: /site-logo.avif description: This blog post provides a detailed overview of a Python programming homework assignment, which includes creating a Mad Libs game, calculating speed and pace, and generating a framed box with user-specified dimensions. -keywords: ["Python", "programming", "homework", "Mad Libs", "speed calculation", "framed box"] +keywords: ["Python", "Programming", "Homework", "Mad Libs", "Speed calculation", "Framed box"] license: comment: true weight: 0 @@ -120,8 +120,6 @@ We will test your code for the values used in our examples as well as a range of {{< link href="HW1.zip" content="HW1.zip" title="Download HW1.zip" download="HW1.zip" card=true >}} -*** - ## Solution ### hw1_part1.py diff --git a/content/en/posts/csci-1100/hw-2/index.md b/content/en/posts/csci-1100/hw-2/index.md index cdfdc5a..6907409 100644 --- a/content/en/posts/csci-1100/hw-2/index.md +++ b/content/en/posts/csci-1100/hw-2/index.md @@ -182,8 +182,6 @@ Test your code well and when you are sure that it works, please submit it as a f {{< link href="HW2.zip" content="HW2.zip" title="Download HW2.zip" download="HW2.zip" card=true >}} -*** - ## Solution ### hw2_part1.py diff --git a/content/en/posts/csci-1200/hw-2/csci-1200-hw-2-flowchart-zh_cn.svg b/content/en/posts/csci-1200/hw-2/csci-1200-hw-2-flowchart-zh_cn.svg new file mode 100644 index 0000000..7d0bfde --- /dev/null +++ b/content/en/posts/csci-1200/hw-2/csci-1200-hw-2-flowchart-zh_cn.svg @@ -0,0 +1,3 @@ + + +

handleCancel()

No

No

Yes

No

Yes

No

Yes

Yes

No

Yes

在 riders 中查找 phoneNumber

找到 Rider?

在 drivers 中查找 phoneNumber

找到 Driver?

输出 'Account does not exist.'

Driver.state == 'On_the_way_to_pickup'?

输出 'You can only cancel...'

Driver 取消: 状态->'Available'
清空 Rider 关联信息

输出 'Your driver X has canceled...'

将 Rider 状态临时重置为 'Ready_to_request'
再自动为 Rider 找新司机 (类似 request )

找到新 Driver?

输出 'Sorry we can not find...'

更新新 Driver='On_the_way_to_pickup',
Rider='Driver_on_the_way'
输出 'We have found the closest driver...'

Rider.state == 'Driver_on_the_way'?

输出 'You can only cancel...'

输出 'Ride request for rider X is now canceled...',
Driver->'Available', Rider->'Ready_to_request'

handleRequest()

No

Yes

No

Yes

Driver_on_the_way

During_the_trip

Ready_to_request

No

Yes

检查 phoneNumber 格式 (xxx-xxx-xxxx)

有效?

输出 'Phone number is invalid.'

在 riders 中查找匹配的 phoneNumber

找到 Rider?

输出 'Account does not exist.'

Rider.state?

输出 'You have already requested a ride...'

输出 'You can not request a ride...'

输出 'Ride requested...' 信息,
在 drivers 中查找匹配车辆类型
且状态为 'Available' 的最近司机

找到可用 Driver?

输出 'Sorry we can not find a driver...'

计算距离, 更新状态:
Driver='On_the_way_to_pickup', Rider='Driver_on_the_way'
输出 'We have found the closest driver...'

Main Program

Yes

No

Yes

No

Start main()

读取命令行参数 'drivers.txt' 'riders.txt' 'output0.txt' 'output1.txt' 'output2.txt' 'phoneNumber' 'command'

loadDrivers(): 读取 'drivers.txt' 到 drivers

loadRiders(): 读取 'riders.txt' 到 riders

command == 'request'?

调用 handleRequest()

command == 'cancel'?

调用 handleCancel()

输出 'Invalid command.'

输出处理结果到 'output0.txt'

将更新后的 drivers 写到 'output1.txt'

将更新后的 riders 写到 'output2.txt'

End main()

\ No newline at end of file diff --git a/content/en/posts/csci-1200/hw-2/index.md b/content/en/posts/csci-1200/hw-2/index.md new file mode 100644 index 0000000..a6b0e0e --- /dev/null +++ b/content/en/posts/csci-1200/hw-2/index.md @@ -0,0 +1,1299 @@ +--- +title: CSCI 1200 - Homework 2 — Designing a Simple Uber +subtitle: +date: 2025-01-22T09:28:20-05:00 +lastmod: 2025-01-22T09:28:20-05:00 +slug: csci-1200-hw-2 +draft: false +author: + name: James + link: https://www.jamesflare.com + email: + avatar: /site-logo.avif +description: This blog post provides a guide on how to implement a simple carpooling application in C++ as part of the CSCI-1200 course assignment. The implementation involves using vectors to store data for handling passenger requests and driver cancellations. +keywords: ["C++", "Programming", "Homework", "String", "Vector", "Class"] +license: +comment: true +weight: 0 +tags: + - CSCI 1200 + - Homework + - RPI + - C++ + - Programming +categories: + - Programming +collections: + - CSCI 1200 +hiddenFromHomePage: false +hiddenFromSearch: false +hiddenFromRss: false +hiddenFromRelated: false +summary: This blog post provides a guide on how to implement a simple carpooling application in C++ as part of the CSCI-1200 course assignment. The implementation involves using vectors to store data for handling passenger requests and driver cancellations. +resources: + - name: featured-image + src: featured-image.jpg + - name: featured-image-preview + src: featured-image-preview.jpg +toc: true +math: false +lightgallery: true +password: +message: +repost: + enable: false + url: + +# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter +--- + + + +## Assignment Requirements + +````markdown +# Homework 2 — Designing a Simple Uber + +In this assignment you will develop a simple ride sharing application called New York Ride. Please read the entire handout before starting to code the assignment. + +## Learning Objectives + +- Practice implementing and working with C++ classes. +- Practice using std::string, std::vector. + +## Specification + +The New York Ride application should support 2 different roles: drivers, riders. Riders can perform two tasks: + +- Request a ride +- Cancel a ride request + +Drivers can perform one task: + +- Cancel a ride request + +*Note*: A commercial ride sharing product like Uber or Lyft of course allows riders and drivers to perform more tasks, but let's be honest, Uber/Lyft has thousands of software engineers, but you only have one person and only have one week to work on this assignment, so let's simplify the tasks. + +## Input Files + +Companies like Uber and Lyft maintain all drivers and riders information in their database, but database is way beyond the scope of this course, and therefore we will just store drivers information and riders information in two simple text files, [drivers.txt](drivers.txt) and [riders.txt](riders.txt). In this assignment you will once again read these files as the input of your program, parse them so as to retrieve drivers and/or riders information, and store them in your own data structures. In this assignment, you must use *std::vector* to store drivers and riders. You are recommended to use one *std::vector* instance to store all drivers, use another *std::vector* instance to store all riders. + +### Driver Information + +The [drivers.txt](drivers.txt) has a format like this: + +```console +Sandra Huang Female 25 853-977-5304 3.1 40.4269 -73.0753 Standard On_the_way_to_pickup Michael Richard 445-915-1645 +Susan Li Female 51 997-217-1025 3.7 40.5863 -73.8684 Premium On_the_way_to_pickup Lucia Kenneth 829-477-7963 +Mary Zhang Female 47 765-620-6297 4.5 40.6988 -73.3988 Economy On_the_way_to_pickup Amy Lee 545-639-2924 +William David Male 37 324-571-7028 3.8 40.2445 -73.5073 Premium Available null null null +Christopher Javier Male 25 218-980-8846 4.5 40.5784 -73.5479 Economy During_the_trip Daniel Chen 820-327-7312 +Dorothy Daniel Female 21 332-586-7858 4 40.6672 -73.2472 Premium During_the_trip Juan Carlos 204-752-4660 +Mateo Andres Male 55 201-564-6348 3.8 40.8771 -73.6288 Standard During_the_trip Karen Michael 534-197-2988 +Dorothy Liu Female 41 507-944-8147 4.5 40.4938 -73.9905 Economy On_the_way_to_pickup Amy Christopher 601-148-3144 +Mateo Robert Male 49 592-397-3458 3.5 40.4106 -73.3736 Economy On_the_way_to_pickup William David 693-200-8952 +Valentina Andres Female 40 299-602-1498 3.3 40.3159 -73.8891 Standard On_the_way_to_pickup Susan Edward 809-345-5043 +``` + +The above is the first 10 lines of the [drivers.txt](drivers.txt) file. It has 13 fields, separated by a space. And these 13 fields are: + +- Driver's first name +- Driver's last name +- Driver's gender +- Driver's age +- Driver's phone number +- Driver's rating +- Driver's current latitude +- Driver's current longitude +- Driver's vehicle type +- Driver's current state +- Rider's first name +- Rider's last name +- Rider's phone number + +The last 3 fields will only be meaningful if a ride request is assigned to this driver. In this assignment, we assume that drivers will accept the request whenever it is assigned to this driver. + +A driver can be in one of the following states: + +- Available (waiting for a request) +- On the way to a pickup location (request accepted) +- During a trip + +When the driver is in an Available state, it means this driver is not assigned a ride request, and therefore is not associated with any rider, and as such, the last 3 fields of this driver will just be +```console +null null null +``` + +### Rider Information + +The [riders.txt](riders.txt) has a format like this: + +```console +Isabella Richard Female 39 301-144-6533 3.2 Top_of_the_Rock 40.7593 -73.979 Gowanus 40.6733 -73.99 Economy Ready_to_request null null null +Juan James Male 47 717-480-4710 3.2 Forest_Hills 40.7196 -73.8448 Park_Slope 40.6728 -73.9778 Standard Driver_on_the_way Melissa Kim 435-773-6289 +Deborah Thomas Female 45 501-380-7736 5 Park_Slope 40.6728 -73.9778 Flatiron_Building 40.7411 -73.9897 Economy Driver_on_the_way Paul Daniel 815-649-6492 +Sofia Steven Female 28 780-650-6240 3 Bay_Ridge 40.635 -74.019 High_Line_Park 40.748 -74.0048 Premium During_the_trip Thomas Edward 557-939-8060 +Anthony Thomas Male 58 302-206-4102 4.3 Prospect_Heights 40.6775 -73.9692 East_River_Park 40.7135 -73.9756 Economy During_the_trip Juan Timothy 471-264-9092 +Lucia Andres Female 59 256-799-3283 3.1 Grand_Central_Terminal 40.7527 -73.9772 Central_Park_Zoo 40.7678 -73.9718 Economy Driver_on_the_way Camila Mark 939-309-5453 +Melissa Christopher Female 28 392-390-8218 4.6 The_High_Line 40.748 -74.0048 The_Vessel 40.7536 -74.0023 Standard Driver_on_the_way Brian Luis 845-708-1986 +William Timothy Male 46 808-688-3264 3.7 Broadway_Theater_District 40.7589 -73.9851 Coney_Island 40.5749 -73.9859 Economy Driver_on_the_way Brenda Christopher 886-285-9845 +Linda Chen Female 60 320-807-7264 4.6 Bushwick 40.6944 -73.9213 Columbia_University 40.8075 -73.9642 Premium Ready_to_request null null null +Brenda Thomas Female 45 470-325-3275 3.2 Bay_Ridge 40.635 -74.019 High_Line_Park 40.748 -74.0048 Premium Driver_on_the_way John Javier 446-656-6614 +``` + +The above is the first 10 lines of the [riders.txt](riders.txt) file. It has 17 fields, separated by a space. And these 17 fields are: + +- Rider's first name +- Rider's last name +- Rider's gender +- Rider's age +- Rider's phone number +- Rider's rating +- The name of the rider's pickup location +- The latitude of the rider's pickup location +- The longitude of the rider's pickup location +- The name of the rider's dropoff location +- The latitude of the rider's dropoff location +- The longitude of the rider's dropoff location +- Rider's vehicle preference +- Rider's current state +- Driver's first name +- Driver's last name +- Driver's phone number + +A rider can be in one of the following states: + +- Ready to request +- Driver on the way (to pickup) +- During a trip + +Ideally, there should be four states, and this other state would be: Ride requested but not yet accepted by any driver. However, as we mentioned, in this assignment, we assume that when a rider issues a request, it will be accepted by a driver, and thus we can exclude this state from our consideration. + +When the rider is in Ready_to_request state, it means no driver is now assigned to this ride request, and therefore, the last 3 fields of this rider will just be + +```console +null null null +``` + +## Commands to Support + +Your program only needs to support two commands: + +### Ride Request + +The first command allows the rider can to send a ride request. + +```console +nyride.exe drivers.txt riders.txt output0.txt output1.txt output2.txt phoneNumber request +``` + +Here + +- drivers.txt is the input file which contains all drivers' information. Your program should never change this file. +- riders.txt is the input file which contains all riders' information. Your program should never change this file. +- output0.txt is the output file where you print messages to rider or driver. +- output1.txt is the output file where you print the updated drivers information, thus this file should have the same format as drivers.txt. +- output2.txt is the output file where you print the updated riders information, thus this file should have the same format as riders.txt. +- phoneNumber. Ideally this should be a phone number which corresponds to one of the riders in the riders.txt whose state is "Ready_to_request"; but life is not always ideal, and how your program should cope with various phone number cases will be described in this section. +- request indicates this is a ride request. + +When this command is run, and + +1. if a driver is found, your program should + +1.1 print the following information into the output0.txt file: +```console +Ride requested for rider Rebecca, looking for an Economy vehicle. +Pick Up Location: Williamsburg, Drop Off Location: Statue_of_Liberty. +We have found the closest driver Elena(4.7) for you. +Elena is now 7.9 miles away from you. +``` +Replace *Rebecca* with the rider's first name, replace *Economy* with the rider's preferred vehicle type, replace *Williamsburg* with the rider's pickup location, and replace *Statue_of_Liberty* with the rider's drop off location. Replace *Elena* with the driver's first name, replace *4.7* with the driver's rating. Replace *7.9* with the driver's distance from the rider. + +1.2 print an updated version of drivers.txt into output1.txt. + +1.3 print an updated version of riders.txt into output2.txt. + +2. if a driver can not be found, your program should print the following message into the output0.txt file: +```console +Ride requested for rider Isabella, looking for a Luxury vehicle. +Pick Up Location: Williamsburg, Drop Off Location: Boerum_Hill. +Sorry we can not find a driver for you at this moment. +``` + +Replace *Isabella* with the rider's first name, replace *Luxury* with the rider's preferred vehicle type, replace Williamsburg with the rider's pickup location, and replace Boerum_Hill with the rider's drop off location. + +3. if the phone number provided from the command line is not in the format of xxx-xxx-xxxx, your program should print the following message to the output0.txt file: +```console +Phone number is invalid. +``` + +4. if the phone number provided from the command line does not match with any of the riders' phone numbers, your program should print the following message to the output0.txt file: +```console +Account does not exist. +``` + +5. if the rider who is issuing this request is in a state of "Driver_on_the_way", your program should print the following message to the output0.txt file: +```console +You have already requested a ride and your driver is on the way to the pickup location. +``` + +6. if the rider who is issuing this request is in a state of "During_the_trip", your program should print the following message to the output0.txt file: +```console +You can not request a ride at this moment as you are already on a trip. +``` + +### Canceling a Request + +The second command allows a rider or a driver to cancel the request. Keep in mind that both the rider and the driver has the right to cancel the request. + +```console +nyride.exe drivers.txt riders.txt output0.txt output1.txt output2.txt phoneNumber cancel +``` + +The only difference between this command and the first command is the last argument here is *cancel*, whereas in the first command, the last argument is *request*. + +When a rider cancels a request, you should just cancel the request; when a driver cancels a request, you should cancel the request, but at the same time, find another closest driver for this rider. + +Only drivers who are on the way to a pickup location, or riders whose driver is on the way, should be allowed to cancel a request. + +When this second command is run, and + +1. if the phone number provided from the command line does not match with any of the riders' phone numbers, and does not match with any of the drivers' phone numbers, your program should print the following message to the output0.txt file: +```console +Account does not exist. +``` + +2. if the canceling request is issued by a rider whose state is NOT Driver_on_the_way, your program should print the following message to the output0.txt file: +```console +You can only cancel a ride request if your driver is currently on the way to the pickup location. +``` + +3. if the canceling request is issued by a driver whose state is NOT On_the_way_to_pickup, your program should print the following message to the output0.txt file: +```console +You can only cancel a ride request if you are currently on the way to the pickup location. +``` + +4. if the canceling request is issued by a rider whose state is Driver_on_the_way, your program should: + +4.1 print the following message to the output0.txt file: +```console +Ride request for rider Brenda is now canceled by the rider. +``` +4.2 print an updated version of drivers.txt into output1.txt: the driver's state should be changed from On_the_way_to_pickup to Available, and the last 3 fields of the driver should be reset to null, meaning that this driver is now not associated with any rider. + +4.3 print an updated version of riders.txt into output2.txt: the rider's state should be changed from Driver_on_the_way to Ready_to_request, and the last 3 fields of the rider should be reset to null, meaning that no driver is now associated with this rider. + +5. if the canceling request is issued by a driver whose state is On_the_way_to_pickup, your program should: + +5.1 print the following message to the output0.txt file: +```console +Your driver Edward has canceled the ride request. We will now find a new driver for you. +Ride requested for rider Angela, looking for a Standard vehicle. +Pick Up Location: The_Met_Cloisters, Drop Off Location: Brooklyn_Navy_Yard. +We have found the closest driver Robert(3.2) for you. +Robert is now 2.1 miles away from you. +``` + +Replace *Edward* with the driver's first name. Replace *Angela* with the rider's first name, replace *Standard* with the rider's preferred vehicle type. Replace *The_Met_Cloisters* with the rider's pickup location, and replace *Brooklyn_Navy_Yard* with the rider's drop off location. Replace *Robert* with the new driver's first name. Replace *3.2* with the new driver's rating. Replace *2.1* with the new driver's distance to the rider. + +5.2 print an updated version of drivers.txt into output1.txt: the old driver's state should be changed from On_the_way_to_pickup to Available. A new driver should be assigned and that new driver's state should be updated accordingly. Also the old driver should no longer be associated with this rider, and the new driver should now be associated with this rider. + +5.3 print an updated version of riders.txt into output2.txt: the rider should now be associated with the new driver. + +## Calculate Distance Based on Haversine Formula + +When finding the driver, you must always find the closest driver whose vehicle type matches with the rider's preference. And when the closest driver is found, you also need to print the distance between this driver and the rider. Thus, you need a way to calculate the distance between two coordinates, and for that purpose, in this assignment, you will use the Haversine Formula, and the code of using the Haversine formula is given below: + +```cpp +// calculate the distance between two coordinates using Haversine formula +double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + const double radiusOfEarth = 6371.0; // Earth's radius in kilometers + + // convert latitude and longitude from degrees to radians + lat1 *= M_PI / 180.0; + lon1 *= M_PI / 180.0; + lat2 *= M_PI / 180.0; + lon2 *= M_PI / 180.0; + + // Haversine formula + double dLat = lat2 - lat1; + double dLon = lon2 - lon1; + double a = sin(dLat / 2.0) * sin(dLat / 2.0) + cos(lat1) * cos(lat2) * sin(dLon / 2.0) * sin(dLon / 2.0); + double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a)); + // distance in kilometers + double distanceKM = radiusOfEarth * c; + // convert it to distance in miles + double distanceMiles = distanceKM * 0.621371; + + return distanceMiles; +} +``` + +This function takes four parameters, which are the latitude and longitude of two geographical locations, and this function returns the distance (in miles) between these two locations. This function calls several math library functions, and therefore you need to include the *cmath* library: + +```cpp +#include +``` + +## Include Guards + +If you are writing more than one class, you may run into strange compiler errors when you compile everything. This may be due to a problem with including your class files, which can be solved as follows: for a header file called myclass.h add these two lines at the very top of the header file: + +```cpp +#ifndef __MYCLASS_H +#define __MYCLASS_H +``` + +and at the very bottom of your .h file, add this line: + +```cpp +#endif +``` + +This technique is known as the "Include Guards". Include guards ensure that the compiler will process a header file only once, no matter how many times it is included. + +## FAQs + +1. Q: Is the requested vehicle type from a rider's perspective a strict requirement for finding a matching driver? Or is it just a preference. Essentially, if a rider requests Economy and there is no available drivers for Economy, but available drivers with other vehicle types, should we output that no driver could be found, or match the nearest driver with different vehicle type? + +A: It is a strict requirement. Do not pick a different vehicle type for the rider. + +2. Q: What is the precision of the output distance? Is it one decimal place or significant figures or holding a certain number of spaces? Do we round up round down or simply trim it down? + +A: Same as Uber. One decimal place. Just trim it. For example, if the distance is 11.4571 miles, you should output 11.4 miles, instead of 11.5 miles. + +## Program Requirements & Submission Details + +In this assignment, you are required to use a vector to store all drivers, and use a vector to store all riders. You are NOT allowed to use any data structures we have not learned so far, especially std::list. Your program should involve the definition of at least two classes that have their own .h and .cpp files, named appropriately. + +Use good coding style when you design and implement your program. Organize your program into functions: +don’t put all the code in main! Be sure to read the [Homework Policies](https://www.cs.rpi.edu/academics/courses/spring25/csci1200/homework_policies.php) as you put the finishing touches on your solution. Be sure to make up new test cases to fully debug your program and don’t forget +to comment your code! Use the provided template [README.txt](./README.txt) file for notes you want the grader to read. +You must do this assignment on your own, as described in the [Collaboration Policy & Academic Integrity](https://www.cs.rpi.edu/academics/courses/spring25/csci1200/academic_integrity.php) page. If you did discuss the problem or error messages, etc. with anyone, please list their names in your +README.txt file. + +**Due Date**: 01/23/2025, Thursday, 10pm. + +## Rubric + +14 pts + +- README.txt Completed (3 pts) + - One of name, collaborators, or hours not filled in. (-1) + - Two or more of name, collaborators, or hours not filled in. (-2) + - No reflection. (-1) +- OVERALL CLASS DECLARATION & IMPLEMENTATION AND CODING STYLE (Good class design, split into a .h and .cpp file. Functions > 1 line are in .cpp file. Organized class implementation and reasonable comments throughout. Correct use of const/const& and of class method const. ) (6 pts) + - No credit (significantly incomplete implementation) (-6) + - Does not successfully declare & use any new classes. (-6) + - Only declares/uses a single class. (-5) + - Putting almost everything in the main function. It's better to create separate functions for different tasks. (-2) + - Improper uses or omissions of const and reference. (-1) + - Function bodies containing more than one statement are placed in the .h file. (okay for templated classes) (-2) + - Functions are not well documented or are poorly commented, in either the .h or the .cpp file. (-1) + - Overly cramped, excessive whitespace, or poor indentation. (-1) + - Poor file organization: Puts more than one class in a file (okay for very small helper classes) (-1) + - Poor choice of variable names: non-descriptive names (e.g. 'vec', 'str', 'var'), single-letter variable names (except single loop counter), etc. (-2) + - Uses global variables. (-1) +- DATA REPRESENTATION (Must use vectors for the implementation.) (5 pts) + - No credit (significantly incomplete implementation). (-5) + - Does not use std::vector to store drivers or riders. (-5) + - Uses std::list or data structures which have not been covered in this class. (-5) + - Member variables are public. (-2) +```` + +## Supporting Files + +{{< link href="ride_sharing.7z" content="ride_sharing.7z" title="Download ride_sharing.7z" download="ride_sharing.7z" card=true >}} + +## Program Design + +Due to the complexity of this assignment, it is best to carefully plan how to implement it before starting. Here I will use two scenarios: "request" and "cancel", respectively designing their individual processes, then using these parts in the main program. Let's call them `handleRequest()` and `handleCancel()`. + +Since the flowchart is quite large, I have temporarily converted it into an image. + +{{< image src="csci-1200-hw-2-flowchart-zh_cn.svg" caption="Flow Chart" >}} + +Mermaid source code as follows: + +```text +flowchart TD + subgraph "Main Program" + A(["Start main()"]) --> B["Read command line arguments 'drivers.txt' 'riders.txt' 'output0.txt' 'output1.txt' 'output2.txt' 'phoneNumber' 'command'"] + B --> C["loadDrivers(): Read 'drivers.txt' into drivers"] + C --> D["loadRiders(): Read 'riders.txt' into riders"] + D --> E{"command == 'request'?"} + E -- Yes --> MR["Call handleRequest()"] + E -- No --> F{"command == 'cancel'?"} + F -- Yes --> MC["Call handleCancel()"] + F -- No --> G["Output 'Invalid command.'"] + MR --> H["Output processing results to 'output0.txt'"] + MC --> H + G --> H + H --> I["Write updated drivers to 'output1.txt'"] + I --> J["Write updated riders to 'output2.txt'"] + J --> K(["End main()"]) + end + + subgraph "handleRequest()" + R1["Check phone number format (xxx-xxx-xxxx)"] --> R2{"Valid?"} + R2 -- No --> R3["Output 'Phone number is invalid.'"] + R2 -- Yes --> R4["Search for matching phone number in riders"] + R4 --> R5{"Find Rider?"} + R5 -- No --> R6["Output 'Account does not exist.'"] + R5 -- Yes --> R7{"Rider.state?"} + R7 -- "Driver_on_the_way" --> R71["Output 'You have already requested a ride...'"] + R7 -- "During_the_trip" --> R72["Output 'You can not request a ride...'"] + R7 -- "Ready_to_request" --> R8["Output 'Ride requested...' information,
Search for matching vehicle type
and state is 'Available' in drivers"] + R8 --> R9{"Find available Driver?"} + R9 -- No --> R10["Output 'Sorry we can not find a driver...'"] + R9 -- Yes --> R11["Calculate distance, update status:
Driver='On_the_way_to_pickup', Rider='Driver_on_the_way'
Output 'We have found the closest driver...`"] + end + + subgraph "handleCancel()" + C1["Search for phone number in riders"] --> C2{"Find Rider?"} + C2 -- No --> C3["Search for phone number in drivers"] + C3 --> C4{"Find Driver?"} + C4 -- No --> C5["Output 'Account does not exist.'"] + C4 -- Yes --> C6{"Driver.state == 'On_the_way_to_pickup'?"} + C6 -- No --> C7["Output 'You can only cancel...'"] + C6 -- Yes --> C8["Driver cancels: state->'Available'
Clear Rider associated information"] + C8 --> C9["Output 'Your driver X has canceled...'"] + C9 --> C10["Temporarily reset Rider state to 'Ready_to_request',
then automatically find new Driver (similar to request)"] + C10 --> C11{"Find new Driver?"} + C11 -- No --> C12["Output 'Sorry we can not find...'"] + C11 -- Yes --> C13["Update new Driver='On_the_way_to_pickup',
Rider='Driver_on_the_way'
Output 'We have found the closest driver...`"] + + C2 -- Yes --> C14{"Rider.state == 'Driver_on_the_way'?"} + C14 -- No --> C15["Output 'You can only cancel...'"] + C14 -- Yes --> C16["Output 'Ride request for rider X is now canceled...',
Driver->'Available', Rider->'Ready_to_request`"] + end +``` + +With the flowchart, we can start implementing them step by step. Of course, you don't necessarily need to write `handleRequest()` and `handleCancel()` as separate functions; implementing their logic directly in `main()` is also acceptable. I am just using this approach for clarity. + +Additionally, we need to design two classes because it's a requirement of the assignment and it makes our implementation easier. + +```mermaid +classDiagram + class Rider { + %% Data members + - firstName : + - lastName : string + - gender : string + - age : int + - phoneNumber : string + - rating : double + - pickupLocationName : string + - pickupLatitude : double + - pickupLongitude : double + - dropoffLocationName : string + - dropoffLatitude : double + - dropoffLongitude : double + - vehiclePref : string + - currentState : string + - driverFirstName : string + - driverLastName : string + - driverPhoneNumber : string + + %% Constructors + + Rider() + + %% Methods + + getFirstName() + + getLastName() + + getGender() + + getAge() + + getPhoneNumber() + + getRating() + + getPickupLocationName() + + getPickupLatitude() + + getPickupLongitude() + + getDropoffLocationName() + + getDropoffLatitude() + + getDropoffLongitude() + + getVehiclePref() + + getCurrentState() + + getDriverFirstName() + + getDriverLastName() + + getDriverPhoneNumber() + + setCurrentState() + + setDriverInfo() + + toFileString() + } + + class Driver { + %% Data members + - firstName : string + - lastName : string + - gender : string + - age : int + - phoneNumber : string + - rating : double + - latitude : double + - longitude : double + - vehicleType : string + - currentState : string + - riderFirstName : string + - riderLastName : string + - riderPhoneNumber : string + + %% Constructors + + Driver() + + %% Methods + + getFirstName() + + getLastName() + + getGender() + + getAge() + + getPhoneNumber() + + getRating() + + getLatitude() + + getLongitude() + + getVehicleType() + + getCurrentState() + + getRiderFirstName() + + getRiderLastName() + + getRiderPhoneNumber() + + setCurrentState() + + setRiderInfo() + + toFileString() + } +``` + +## Pitfalls + +1. When printing `output0.txt`, the phrase "looking for" should be followed by a rider's preferred vehicle type, which may contain vowels. Therefore, you need to determine whether to use "a" or "an". This is a small issue but don't forget it. I used a function to return "a" or "an". + + ```cpp + std::string autoAAn(const std::string &word) { + if (word.empty()) return ""; + if (word[0] == 'A' || word[0] == 'E' || word[0] == 'I' || word[0] == 'O' || word[0] == 'U') { + return "an"; + } + return "a"; + } + ``` + + Then, use `ostringstream` from `` to concatenate fields obtained from the Rider class. The following code demonstrates this logic and structure. + + ```cpp + #include + //... + Rider &r = riders[rIdx]; //just consider `r` as your rider class + std::ostringstream msg; + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + ``` + +2. Be very careful when handling driver states, as changes need to be updated immediately because some logic depends on the current state of the driver. For example, when a driver transitions from `On_the_way_to_pickup` to `Available`, clear Rider associated information and automatically find a new Driver for the Rider. When re-locating a new Driver, avoid finding previously assigned Drivers. +3. Class variables should not be public (as per assignment requirements); access them through methods rather than directly manipulating the variables. +4. According to the assignment requirements, we cannot use `auto` keyword, which necessitates modifying for-loops as follows: + + ```diff + void exportDrivers(const std::string &filename, const std::vector &drivers) { + //... + std::ofstream ofs(filename); + - for (const auto &d : drivers) { + + for (int i = 0; i < (int)drivers.size(); i++) { + + const Driver &d = drivers[i]; + ofs << d.toFileString() << "\n"; + } + ofs.close(); + } + ``` + +## Solution + +### nyrider.cpp + +```cpp +//An implement of CSCI-1200 HW2 Ride Sharing +//Author: JamesFlare +//Date: 2025/1/20 +//#include +//#include +#include +#include +#include +#include +#include +#include +#include + +#include "Driver.h" +#include "Rider.h" + +void debug_print(const std::string &msg) { + std::cout << "DEBUG: " << msg << std::endl; +} + +bool isPhoneNumberValid(const std::string &phone) +{ + if (phone.size() != 12) return false; + //xxx-xxx-xxxx + for (int i = 0; i < 12; i++) { + if (i == 3 || i == 7) { + if (phone[i] != '-') return false; + } else { + if (!std::isdigit((unsigned char)phone[i])) return false; + } + } + return true; +} + +void loadDrivers(std::ifstream &ifs, std::vector &drivers) { + //read the file line by line, total of 13 + while (!ifs.eof()) { + std::string fName, lName, gender, phone, vehicleType, state; + std::string rF, rL, rP; + int age; + double rating, lat, lon; + ifs >> fName >> lName >> gender >> age >> phone >> rating >> lat >> lon + >> vehicleType >> state >> rF >> rL >> rP; + if (!ifs.fail()) { + //change "null" to empty string + if (rF == "null") rF = ""; + if (rL == "null") rL = ""; + if (rP == "null") rP = ""; + //create driver + Driver d(fName, lName, gender, age, phone, rating, lat, lon, + vehicleType, state, rF, rL, rP); + drivers.push_back(d); + } + } + ifs.close(); +} + +void loadRiders(std::ifstream &ifs, std::vector &riders) { + //read the file line by line, total of 17 + while (!ifs.eof()) { + std::string fName, lName, gender, phone, pickupLoc, dropoffLoc, vPref, state; + std::string dF, dL, dP; + int age; + double rating, pickupLat, pickupLon, dropoffLat, dropoffLon; + ifs >> fName >> lName >> gender >> age >> phone >> rating + >> pickupLoc >> pickupLat >> pickupLon + >> dropoffLoc >> dropoffLat >> dropoffLon + >> vPref >> state + >> dF >> dL >> dP; + if (!ifs.fail()) { + //fill null with empty string + if (dF == "null") dF = ""; + if (dL == "null") dL = ""; + if (dP == "null") dP = ""; + //create rider + Rider r(fName, lName, gender, age, phone, rating, + pickupLoc, pickupLat, pickupLon, + dropoffLoc, dropoffLat, dropoffLon, + vPref, state, dF, dL, dP); + riders.push_back(r); + } + } + ifs.close(); +} + +std::ifstream loadFile(const std::string &filename) { + //read file and return ifstream + std::ifstream ifs(filename); + if (!ifs) { + std::cerr << "Error opening file: " << filename << std::endl; + exit(1); + } + return ifs; +} + +void saveFile(const std::string &filename, const std::string &msg) { + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening file: " << filename << std::endl; + exit(1); + } + ofs << msg; + ofs.close(); +} + +void exportDrivers(const std::string &filename, const std::vector &drivers) { + //save drivers to file + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening output file: " << filename << std::endl; + return; + } + for (int i = 0; i < (int)drivers.size(); i++) { + const Driver &d = drivers[i]; + ofs << d.toFileString() << "\n"; + } + ofs.close(); +} + +void exportRiders(const std::string &filename, const std::vector &riders) { + //save riders to file + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening output file: " << filename << std::endl; + return; + } + for (int i = 0; i < (int)riders.size(); i++) { + const Rider &r = riders[i]; + ofs << r.toFileString() << "\n"; + } + ofs.close(); +} + +// calculate the distance between two coordinates using Haversine formula +double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + const double radiusOfEarth = 6371.0; // Earth's radius in kilometers + // convert latitude and longitude from degrees to radians + lat1 *= M_PI / 180.0; + lon1 *= M_PI / 180.0; + lat2 *= M_PI / 180.0; + lon2 *= M_PI / 180.0; + // Haversine formula + double dLat = lat2 - lat1; + double dLon = lon2 - lon1; + double a = sin(dLat / 2.0) * sin(dLat / 2.0) + cos(lat1) * cos(lat2) * sin(dLon / 2.0) * sin(dLon / 2.0); + double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a)); + // distance in kilometers + double distanceKM = radiusOfEarth * c; + // convert it to distance in miles + double distanceMiles = distanceKM * 0.621371; + + return distanceMiles; +} + +int findClosestDriver(const std::vector &drivers, + const Rider &rider) { + double minDistance = 1e9; + int bestIndex = -1; + for (int i = 0; i < (int)drivers.size(); i++) { + const Driver &drv = drivers[i]; + if (drv.getCurrentState() == "Available" && + drv.getVehicleType() == rider.getVehiclePref()) { + double dist = calculateDistance(drv.getLatitude(), drv.getLongitude(), + rider.getPickupLatitude(), rider.getPickupLongitude()); + if (dist < minDistance) { + minDistance = dist; + bestIndex = i; + } + } + } + return bestIndex; +} + +int findRiderIndexByPhone(const std::vector &riders, const std::string &phone) { + for (int i = 0; i < (int)riders.size(); i++) { + if (riders[i].getPhoneNumber() == phone) { + return i; + } + } + return -1; +} + +int findDriverIndexByPhone(const std::vector &drivers, const std::string &phone) { + for (int i = 0; i < (int)drivers.size(); i++) { + if (drivers[i].getPhoneNumber() == phone) { + return i; + } + } + return -1; +} + +std::string autoAAn(const std::string &word) { + if (word.empty()) return ""; + if (word[0] == 'A' || word[0] == 'E' || word[0] == 'I' || word[0] == 'O' || word[0] == 'U') { + return "an"; + } + return "a"; +} + +int main(int argc, char *argv[]) { + //take 3 arguments + if (argc < 8) { + std::cout << "Usage: nyride drivers.txt riders.txt output0.txt output1.txt output2.txt phoneNumber [request|cancel]\n" << std::endl; + return 1; + } + //load arguments + const std::string drivers_fName = argv[1]; + const std::string riders_fName = argv[2]; + std::string msg_fName = argv[3]; + std::string updated_drivers_fName = argv[4]; + std::string updated_riders_fName = argv[5]; + std::string phone_number = argv[6]; + std::string command = argv[7]; + //turn on debug mode is last argument is debug + bool debug_mode = false; + if (std::string(argv[argc - 1]) == "debug") { + debug_mode = true; + } + + if (debug_mode) { + debug_print("drivers_fName = " + drivers_fName); + debug_print("riders_fName = " + riders_fName); + debug_print("msg_fName = " + msg_fName); + debug_print("updated_drivers_fName = " + updated_drivers_fName); + debug_print("updated_riders_fName = " + updated_riders_fName); + debug_print("phone_number = " + phone_number); + debug_print("command = " + command); + } + //load drivers + std::vector drivers; + std::ifstream drivers_file = loadFile(drivers_fName); + loadDrivers(drivers_file, drivers); + //load riders + std::vector riders; + std::ifstream riders_file = loadFile(riders_fName); + loadRiders(riders_file, riders); + if (debug_mode) { + debug_print("drivers.size() = " + std::to_string(drivers.size())); + debug_print("riders.size() = " + std::to_string(riders.size())); + } + //check if phone number is valid + std::ostringstream msg; + if (!isPhoneNumberValid(phone_number)) { + std::cout << "Error: Invalid phone number" << std::endl; + msg << "Phone number is invalid.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //check if command is valid + if (command != "request" && command != "cancel") { + std::cout << "Error: Invalid command" << std::endl; + return 1; + } else if (command == "request") { + //for request cases + int rIdx = findRiderIndexByPhone(riders, phone_number); + if (rIdx == -1) { + //if rider does not exist + msg << "Account does not exist.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + Rider &r = riders[rIdx]; + //check rider + if (r.getCurrentState() == "Driver_on_the_way") { + msg << "You have already requested a ride and your driver is on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + if (r.getCurrentState() == "During_the_trip") { + msg << "You can not request a ride at this moment as you are already on a trip.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + if (r.getCurrentState() == "Ready_to_request") { + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + //find closest driver + int dIdx = findClosestDriver(drivers, r); + if (dIdx == -1) { + //no driver + msg << "Sorry we can not find a driver for you at this moment.\n"; + } else { + Driver &d = drivers[dIdx]; + double dist = calculateDistance(d.getLatitude(), d.getLongitude(), + r.getPickupLatitude(), r.getPickupLongitude()); + dist = (int)(dist * 10) / 10.0; //cut to 1 decimal + msg << "We have found the closest driver " << d.getFirstName() << "(" + << std::fixed << std::setprecision(1) << d.getRating() << ") for you.\n" + << d.getFirstName() << " is now " + << std::fixed << std::setprecision(1) << dist + << " miles away from you.\n"; + //update status + d.setCurrentState("On_the_way_to_pickup"); + d.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber()); + r.setCurrentState("Driver_on_the_way"); + r.setDriverInfo(d.getFirstName(), d.getLastName(), d.getPhoneNumber()); + } + } + } else if (command == "cancel") { + //for cancel cases + //find phone_number in riders + int rIdx = findRiderIndexByPhone(riders, phone_number); + if (rIdx == -1) { + //in case of driver's cancel + int dIdx = findDriverIndexByPhone(drivers, phone_number); + if (dIdx == -1) { + //in case of not both rider and driver + msg << "Account does not exist.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + Driver &driver = drivers[dIdx]; + if (driver.getCurrentState() != "On_the_way_to_pickup") { + msg << "You can only cancel a ride request if you are currently on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //get rider's phone number + std::string rPh = driver.getRiderPhoneNumber(); + //clean driver's rider info + driver.setCurrentState("Available"); + driver.setRiderInfo("", "", ""); + msg << "Your driver " << driver.getFirstName() + << " has canceled the ride request. We will now find a new driver for you.\n"; + //find rider + int theRiderIdx = findRiderIndexByPhone(riders, rPh); + Rider &r = riders[theRiderIdx]; + //reset rider + r.setCurrentState("Ready_to_request"); + r.setDriverInfo("", "", ""); + //find a new driver + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + int newDIdx = findClosestDriver(drivers, r); + if (newDIdx == -1) { + msg << "Sorry we can not find a driver for you at this moment.\n"; + } else { + Driver &newDriver = drivers[newDIdx]; + double dist = calculateDistance(newDriver.getLatitude(), newDriver.getLongitude(), + r.getPickupLatitude(), r.getPickupLongitude()); + dist = (int)(dist * 10) / 10.0; //cut to 1 decimal + msg << "We have found the closest driver " << newDriver.getFirstName() << "(" + << std::fixed << std::setprecision(1) << newDriver.getRating() << ") for you.\n" + << newDriver.getFirstName() << " is now " + << std::fixed << std::setprecision(1) << dist + << " miles away from you.\n"; + //update driver's status + newDriver.setCurrentState("On_the_way_to_pickup"); + newDriver.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber()); + //update rider's status + r.setCurrentState("Driver_on_the_way"); + r.setDriverInfo(newDriver.getFirstName(), newDriver.getLastName(), newDriver.getPhoneNumber()); + } + } else { + //in case of rider's cancel + Rider &rider = riders[rIdx]; + if (rider.getCurrentState() != "Driver_on_the_way") { + msg << "You can only cancel a ride request if your driver is currently on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //find driver's phone_number + std::string dPh = rider.getDriverPhoneNumber(); + msg << "Ride request for rider " << rider.getFirstName() + << " is now canceled by the rider.\n"; + //set driver's status to Available + int dIdx = findDriverIndexByPhone(drivers, dPh); + if (dIdx != -1) { + Driver &drv = drivers[dIdx]; + drv.setCurrentState("Available"); + drv.setRiderInfo("", "", ""); + } + //set rider's status to Ready_to_request + rider.setCurrentState("Ready_to_request"); + rider.setDriverInfo("", "", ""); + } + } + //save msg + saveFile(msg_fName, msg.str()); + //save updated drivers and riders + exportDrivers(updated_drivers_fName, drivers); + exportRiders(updated_riders_fName, riders); + + return 0; +} +``` + +### Rider.h + +```cpp +#ifndef __RIDER_H +#define __RIDER_H + +#include + +class Rider { +private: + std::string firstName; + std::string lastName; + std::string gender; + int age; + std::string phoneNumber; + double rating; + std::string pickupLocationName; + double pickupLatitude; + double pickupLongitude; + std::string dropoffLocationName; + double dropoffLatitude; + double dropoffLongitude; + std::string vehiclePref; + std::string currentState; + //driver's info + std::string driverFirstName; + std::string driverLastName; + std::string driverPhoneNumber; + +public: + //init + Rider(); + Rider(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, const std::string &pickupLocName, double pickupLat, double pickupLon, + const std::string &dropoffLocName, double dropoffLat, double dropoffLon, + const std::string &vehiclePref, const std::string &state, + const std::string &dF, const std::string &dL, const std::string &dP); + + //getters & setters + const std::string& getFirstName() const; + const std::string& getLastName() const; + const std::string& getGender() const; + int getAge() const; + const std::string& getPhoneNumber() const; + double getRating() const; + const std::string& getPickupLocationName() const; + double getPickupLatitude() const; + double getPickupLongitude() const; + const std::string& getDropoffLocationName() const; + double getDropoffLatitude() const; + double getDropoffLongitude() const; + const std::string& getVehiclePref() const; + const std::string& getCurrentState() const; + const std::string& getDriverFirstName() const; + const std::string& getDriverLastName() const; + const std::string& getDriverPhoneNumber() const; + + void setCurrentState(const std::string &state); + void setDriverInfo(const std::string &df, const std::string &dl, const std::string &dp); + //return a string representation of the rider + std::string toFileString() const; +}; + +#endif +``` + +### Rider.cpp + +```cpp +#include "Rider.h" +#include + +Rider::Rider() + : age(0), rating(0.0), pickupLatitude(0.0), pickupLongitude(0.0), + dropoffLatitude(0.0), dropoffLongitude(0.0) {} + +Rider::Rider(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, const std::string &pickupLocName, double pickupLat, double pickupLon, + const std::string &dropoffLocName, double dropoffLat, double dropoffLon, + const std::string &vPref, const std::string &state, + const std::string &dF, const std::string &dL, const std::string &dP) + : firstName(fName), lastName(lName), gender(gen), age(a), + phoneNumber(phone), rating(r), + pickupLocationName(pickupLocName), pickupLatitude(pickupLat), pickupLongitude(pickupLon), + dropoffLocationName(dropoffLocName), dropoffLatitude(dropoffLat), dropoffLongitude(dropoffLon), + vehiclePref(vPref), currentState(state), + driverFirstName(dF), driverLastName(dL), driverPhoneNumber(dP) {} + +const std::string& Rider::getFirstName() const { return firstName; } +const std::string& Rider::getLastName() const { return lastName; } +const std::string& Rider::getGender() const { return gender; } +int Rider::getAge() const { return age; } +const std::string& Rider::getPhoneNumber() const { return phoneNumber; } +double Rider::getRating() const { return rating; } +const std::string& Rider::getPickupLocationName() const { return pickupLocationName; } +double Rider::getPickupLatitude() const { return pickupLatitude; } +double Rider::getPickupLongitude() const { return pickupLongitude; } +const std::string& Rider::getDropoffLocationName() const { return dropoffLocationName; } +double Rider::getDropoffLatitude() const { return dropoffLatitude; } +double Rider::getDropoffLongitude() const { return dropoffLongitude; } +const std::string& Rider::getVehiclePref() const { return vehiclePref; } +const std::string& Rider::getCurrentState() const { return currentState; } +const std::string& Rider::getDriverFirstName() const { return driverFirstName; } +const std::string& Rider::getDriverLastName() const { return driverLastName; } +const std::string& Rider::getDriverPhoneNumber() const { return driverPhoneNumber; } + +void Rider::setCurrentState(const std::string &state) { + currentState = state; +} + +void Rider::setDriverInfo(const std::string &df, const std::string &dl, const std::string &dp) { + driverFirstName = df; + driverLastName = dl; + driverPhoneNumber = dp; +} + +std::string Rider::toFileString() const { + //Isabella + //Richard + //Female + //39 + //301-144-6533 + //3.2 + //Top_of_the_Rock + //40.7593 -73.979 + //Gowanus + //40.6733 + //-73.99 + //Economy + //Ready_to_request + //null + //null + //null + std::ostringstream oss; + oss << firstName << " " + << lastName << " " + << gender << " " + << age << " " + << phoneNumber << " " + << rating << " " + << pickupLocationName << " " + << pickupLatitude << " " + << pickupLongitude << " " + << dropoffLocationName << " " + << dropoffLatitude << " " + << dropoffLongitude << " " + << vehiclePref << " " + << currentState << " " + << (driverFirstName.empty() ? "null" : driverFirstName) << " " + << (driverLastName.empty() ? "null" : driverLastName) << " " + << (driverPhoneNumber.empty() ? "null" : driverPhoneNumber); + + return oss.str(); +} +``` + +### Driver.h + +```cpp +#ifndef __DRIVER_H +#define __DRIVER_H + +#include + +class Driver { +private: + std::string firstName; + std::string lastName; + std::string gender; + int age; + std::string phoneNumber; + double rating; + double latitude; + double longitude; + std::string vehicleType; + std::string currentState; + //rider's info + std::string riderFirstName; + std::string riderLastName; + std::string riderPhoneNumber; + +public: + //init + Driver(); + Driver(const std::string &firstName, const std::string &lastName, + const std::string &gender, int age, const std::string &phoneNumber, + double rating, double latitude, double longitude, + const std::string &vehicleType, const std::string ¤tState, + const std::string &riderFirstName, const std::string &riderLastName, + const std::string &riderPhoneNumber); + + //getters & setters + const std::string& getFirstName() const; + const std::string& getLastName() const; + const std::string& getGender() const; + int getAge() const; + const std::string& getPhoneNumber() const; + double getRating() const; + double getLatitude() const; + double getLongitude() const; + const std::string& getVehicleType() const; + const std::string& getCurrentState() const; + const std::string& getRiderFirstName() const; + const std::string& getRiderLastName() const; + const std::string& getRiderPhoneNumber() const; + + void setCurrentState(const std::string &state); + void setRiderInfo(const std::string &rf, const std::string &rl, const std::string &rp); + //return a string representation of the driver + std::string toFileString() const; +}; + +#endif +``` + +### Driver.cpp + +```cpp +#include "Driver.h" +#include + +Driver::Driver() : age(0), rating(0.0), latitude(0.0), longitude(0.0) {} + +Driver::Driver(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, double lat, double lon, + const std::string &vehType, const std::string &state, + const std::string &rF, const std::string &rL, + const std::string &rP) + : firstName(fName), lastName(lName), gender(gen), age(a), + phoneNumber(phone), rating(r), latitude(lat), longitude(lon), + vehicleType(vehType), currentState(state), + riderFirstName(rF), riderLastName(rL), riderPhoneNumber(rP) {} + +//getters +const std::string& Driver::getFirstName() const { return firstName; } +const std::string& Driver::getLastName() const { return lastName; } +const std::string& Driver::getGender() const { return gender; } +int Driver::getAge() const { return age; } +const std::string& Driver::getPhoneNumber() const { return phoneNumber; } +double Driver::getRating() const { return rating; } +double Driver::getLatitude() const { return latitude; } +double Driver::getLongitude() const { return longitude; } +const std::string& Driver::getVehicleType() const { return vehicleType; } +const std::string& Driver::getCurrentState() const { return currentState; } +const std::string& Driver::getRiderFirstName() const { return riderFirstName; } +const std::string& Driver::getRiderLastName() const { return riderLastName; } +const std::string& Driver::getRiderPhoneNumber() const { return riderPhoneNumber; } + +//setters +void Driver::setCurrentState(const std::string &state) { + currentState = state; +} + +void Driver::setRiderInfo(const std::string &rf, const std::string &rl, const std::string &rp) { + riderFirstName = rf; + riderLastName = rl; + riderPhoneNumber = rp; +} + +std::string Driver::toFileString() const { + //Sandra + //Huang + //Female + //25 + //853-977-5304 + //3.1 + //40.4269 + //-73.0753 + //Standard + //On_the_way_to_pickup + //Michael + //Richard + //445-915-1645 + std::ostringstream oss; + oss << firstName << " " + << lastName << " " + << gender << " " + << age << " " + << phoneNumber << " " + << rating << " " + << latitude << " " + << longitude << " " + << vehicleType << " " + << currentState << " " + << (riderFirstName.empty() ? "null" : riderFirstName) << " " + << (riderLastName.empty() ? "null" : riderLastName) << " " + << (riderPhoneNumber.empty() ? "null" : riderPhoneNumber); + return oss.str(); +} +``` diff --git a/content/en/posts/csci-1200/hw-2/ride_sharing.7z b/content/en/posts/csci-1200/hw-2/ride_sharing.7z new file mode 100644 index 0000000000000000000000000000000000000000..3f66834088b94f8b5de705cb2b86f172d75edd56 GIT binary patch literal 45049 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¬^0t%z1KddjY^K>o&X&9jWGQ$ zb>F}vTy_WKai3OWy56(Fwi*-v_o!TQvdZEL4+4TQyKtss{e*U@BNIME%#@8=*D3sN zW$^Pa-eHGBbIv#{7PS~%TBXGySPYj`G@XwawTqvM0`3}!N!Uu8U*+@ruK|TWvV6R3 zfdnfl+QmcjR-Ku(b3Ubna9CBrlS7(hFU1ZZ|NT|6o7J9X8h~#kn{gQUUn>D7z9#&& zV%3sa-D<~Vfv7_v_m(=53Z+6VBajTi($hC=uS6Q^Fdv{R60R0KiGx1z1+5Z+rL240 zVXP^BcJqb)P~ZA!tIY>bziT1Fh2B7xIO5#rM-uwe!G)+v8=-D!P6(oY>sMpyR_k2* zs8?{2U_x+bUvpXD$_&u4<8J;W1g@U_g>V?GnELoC)J9K#;Ish5*9}Q-Dwb%2Nlo zG;uVzCFT}IzM0ur)!0wWgjPQ1V-#BFv+gncjO{e?PkCjYUBCzby0Phtx|bQ~K3WYi zaeL0RL$CcHOtc{JW%VAOO4SCX9zN9Nsy8qm5fXW}Rm^vQKeEhy+2&DC0;9KU>i7CD zy)A}PaXd$bner|PgOlTX1bS`Qqcrv#@rD!trvCkWo{u!EUJ0oDJj}SF&Yw#f)=BLT z-3oN(eKt}>m)`-5}51<{iLI6IPW2!z9?>({xPt!8H}g7 zFn!0N&NQj+F!#m90pk%c87|X+J5?oX_qTue7NASRoo| zAFX$9e%X@m*FUeK&FQ9grtM~^uFfkzKB&7=QirAKF(_+Tg{yMn`)E&T?A12Gv=yfR zFlLd}j%$+Nd9jmjrac8~Dh++M!;onO-&C9rfT|7@Tjah)f!83RXOK1|OuhlRO_JuC z6O)MsfB_GtBaCk&&v-czj2llR5b8oWm$A~af6njwH5Y#d7SE<#1p)2y#DBXYqp zNT4uwH29#8bSjOLq%Xv!L#_zKhHls7#sgO)Hh?0lfGmDqzIMqR5$IWEhRgZ-`u=?+ zz(1^jDYiTsPm}w=ZKW{{Hf?44GU4va;@57w?o8!wZ1&FUmxqdbRpkFt-ZyTAJ!=y~ zaLrF}=C0zFS5;w5N{1U1z@)x@w!+nB8ER|1k+7mF>n!^U{DW4_W!O`67U0~0baR_> z=L?xw>r~Fq^KEH=NgWkDvX>i07Kb&}jmEn3qubqWoX8TZ)*6ov(aq>x=Y;k=P8|XH z3IpunT79qn5G8hhx(0n+`Q3nk#xTDZEmWd_^iq34bSJY0f0&-4lg^NvP6(f=b(L?3 zUL?XzmK|NhglpzBlQsaW9{mQc_07RaT*O)94gFBx!yI!BJWS}s#!5*`#8TDT7vzf7 zX4msl%Of1%0n;)ja@kv&We`2%&n9iH{fJP+6vOI}30!2uE)N#uD}0H(qT`fo(6QW`>UNuy|wlG$BFCv`0+J^14K z>KH1!&$!!JdHpr1g75MkW#+9UO!xqR)k!(;nQQ)ZnxHK^T5cJg`ju1;4z`bR<$#XuBF9h$9`P0bVQI5|nL{ zbuvwPh#nU*eE?ev@pk&KYIdBh8tM{Ncj@Mw3(q`mPx$^dp=ZowIru6>^rX4BJXUHB zSjR(?dG@;GOW%_!pR<`x>fX8K23ZxSoTBVj)!r?THoVh)zX1PJD#duMix2{aNcQE@ zlO%nv0|z7Pb9FYrypFk@@0QbKM)4#LD;5I0J5A3)G3YpS!vEq^v~h{#ssT%y3J zOLx078;ze`f|VU0OJ5b`@~XQxRI_i+H9!CwT&m0B#e;vA`PVJ3#)?$X z3YOK?<#DVCEO&R>oEeu=^X}$g2(0X|GD{vBslwc=%;3u1A;n!?jczw=>m(@PBXWS& z1@p%1DGbfFafT2eUWSP^tw&=mG;^?!Dy%K#b@Jik;~g@0A;CEoy}q10V)P2$>pP2p z2b93oIu%8OVUD+JqJwNx5z<7?JgzygWOCK3j4S$0$ff)gvTqdMG*okJF`GcRbEC-N z{*xd57fMENkm=mOynSlM_d2BW#b#-YY90PF_qkCQr3d_PwUiS6fw7kKOVUat38$KR zkebKUEFE>nd_;VWI{os5>>{-*DFP&b~yRNo{Ijcb<47T%I;3n`o!_4xI|B(4T-A$#8Yhxk$W`@-Q zcc!VQRv~3V+c6o+K{!%EOeIql<-NbB&ilj7=7B<{p2W+J6Q(kTo#htsDo)JK^yN~E zcLKdEvTwf?GA6&FPS$e#s3{xeeuzBJ$kSW&$CPO`BK329JwuHarEyBwT*g6?Z5K1X z|4_Q6Z)A2~4nrN~C#%lk*u#T^VHxEVy2z;mFGhZymR+lSG!RRuG1oTqjQL)3e7{?H zc)Go`AbsHh&S_N%`hGx+1bH|aU;P%d$1SDBCxfYkXR@@=BJI;>U9DNr!@u}aa|M%h zv`SR4lQT{W?&j(NheF+>?%FFRgz=5th~CV$P9s2u+!IL|Nf}zczQk?%SmyumqkhE% zr%>_>16ha8Jq4~HJdAU`XK=exjyAzsbt)1a^C=)tr|@S1(oTUtu_7)+R4#P3IvMai z`>ZVb@U-V)NR*||4ws;45AFiFzUqj=cc;EV9WML=J z#Td&4LN;Knvj!;@M^=x#bSU$oeg26-;JI)vVx<(o!n{oUx`u2a337VuEZxFF&n%owE%?{OHT0h+q&Lj> zquH5S$$bLiOA42di0rTCL-H+_D!GTLMIxfje-`f68L#S-BSbLtG_*S?km|4 zhg2o(yq7Q%-#0BucgE-Ygq(FJ_7o#-EZ+KvQ@VxKp9`}QjI|}NGvVa_`o4yroA$y- zua_S~OGF_#{xarumavo%v%6WTMc*gbsLD4LxwwscB&um6EHpE_Mp3Cqx#7QykokM| zycJxK8q#j}R-s&Ody%c_e(X{iTLj{uH6*l*wk}RtK2JJ5TQjcOJ@!3v;cut^NZR0A zY7c-i>_K)EKQS}>1b;1-15jaW`GXu!HJVupUtwPYn^tGGYgW=IWI6#5U#~IR zioP)@z<-JeR?fd>#KJJ$1ulrR{vk}*FMQ6mX@IlNzUz@uuG#q!aM*sR?0GH4_qj**5~DvON3P!Vg;~K@MDj578eE6g2_FUcZg=ApDhQKrKpwiJ@C| zwv%{B*)RtYHGDmZ)mx@M(P&I-3BHUEL8jaibfKkX92by_Yi+xUdFE#*99ASO{A`7I zdR<{~{eY1nu;I?oQhYIm224kd8lwn=_0~w10aS-YVXQH?-*p4Q ze=T}>$qg_~xK*ScEMp0s;ATvR!jQj!m|mbe)8I}}@XEhl3hPpRlp_Q(rj3ji6qc$q zM@Fnr-lP{4MF&=3PaKd;gB0DFFHi~{(nm1x;F=6M++ct6@rhC77bKH|s=RbkA*@HO zRn|G`W$lOW&dn6?S7UL@>%}vQTg#{%Gdv)h_e_I*jXxVSGSc>Jk?m+7m zQ-Oo>Sbdhe?=DQU-UGdh=w)7Q?k@Pwn`#u-!>g#nN12OrjTMF$u<`vI*yv8jU61SE zR3G-!IuW%(JFqmSpS!wN`mhI~kqlI`nfz6;s~oLg0I({i%R<(pO~r z;Q|kYOrS|E_~c>(+*p?OG($OyD{W?`px;SEq`_h2Byh&#ju$X!Bz)eA#sd8Qf6DnS zCXs@=u3+FJ&h8Q17Gc_{5?s}R}ZniuvJ+Ku-7~O5X2{?3)<#bH&Q&wQUzKT0KO@QX`ntFy>i8+>5dRf zcKcXmU!IUe3>B`BjqlOh!?LOWx*&CmC=hnJ2X(2;U)l_JL4h?zTIeith~;ApdY@Ae zcQ}pD!iT$ePyS>{m^4hndxX!?A^N&GoiD;51(wh9mIiHTT^gY9O~`fC*jc#Oc~WYy z#*`NDw0H`ckUB0b{m7w14O9el?W#lR8bK{++WD zU9S?A0fdyrMqt9%t3tm9OHWNl{&6&MzIJ8)YllQIM>Op<(unybD9dYKv7Iu4M8Ujl z>^HU3%dF|Rs8zFbviHS3%}sNMmGJNC3q_-st2R7psuLOI!6 zH0`m9^M8cZ>L)B}nKMj{@Oz5X@K*Zz?wQmqgvWuDlW&420?ZP3_UMR8zyh7oNh|_R@AP(YL%q)^!7l=05Yzx?JinUYAU19VR+QmDfZ*YMBRQD zvTeH00WJp1rw^Go?s;(Q)kY8g1>JoMXkT3-b1-!-qDV%Y_!9tlN4I5)tCacbE5_!p zRQ%XJDMO89{d1yAGK`|$UNCO!eKdqQLCep-0}E!|E{_WNrG3qxGzH+LeQf2IT_PK= zla!-lW}T$eH!3O2*H;oM3ovqT>CrmIRSVd$gm z&T2*VDEHoKM$1L!QpWm^t4mOwhw4c@=8o$`d-YAsoOwFQW#gK~j0)dX_c<_zyw=e{ z2hR1~L=zS)tEQa2>&O)d~hla8}TbB&7tO#uay45Ye>wGNuUFHav zdg#U8OI{myK~PV{%7`wGQ$gOw_6BQX5sxZR5rhvl*sfYvd@}L4NICfPuJVy0Bs~)b z=7cs$;l5r=p){kF7q@h<-`ZtZ-4UzB@xbiDmRNtg+RkQ)f2}4tmlWP|D3T_r+9~>% zD-63SV|TqfRN{E}$8f!R-f`pAMx%Qe;8s8Wy(Bq4D*@>NT{vI)S-N%;%C6==m}MR(BaVP22u zkHGCZieIxAys$Av-5x3)&S>k$VYu9$K^8u*+x`t~CSFIg<(||%{doqe1!K{CCLQiO z_Mehws&v8U1*|7zm8~ttK4~{!zdyIppP$@@N53u_&CU?0wnajLg2HT{zG!{fLwL(g*fnEyu*sH>L4^v;tmvMga&fdB8ZTqE9XfUOsmHDZeq-wTVx)T>=5Iu>mDNFf6 zA7IXhWe)i@1c3tHa}H)(qt7W z(yIdbaOAwra~c-|`NO^bHx~H2UNvY6L4P!J-F!j!TnJ#CZA4ZO)veA9o3jXOKKnfv zCz(Saq*bg9(Por+1S{Au;eU>4>pTw$GlL)5JW+CaFJFs%aizeEMi(m#;~c2es2)ZsPw? zO4lF|<;RDqsn!XHI*AKjwC?}(A2y=e@{cUUlzS4YeBo;;n!C_?=5)9QrS5<2- zb~G?fa+o^`2<_e1l#Pg|B-cwN)o7Xdp@zI@02xDauJ)xy4_pmjO??uZ%7hSA#qffu z{>qWCml#%|(D|8N9dEQKsM-WauXdF@&QYyG1N^fOV=HFjN5@q*Z?cBAm*I(C-7G7- zz?H~=YFT_G7cXb;-^5uD-sWt$kY!Wt^Pe}TZ$FS{@M(c#!ns@yPi{X)`Tdb`L$)|y zK>klrcrMOZGp3&4PWr9#=Kn8ns+Le$Ks59|x-?Fq@dQpZ>KJtwQ;S#nQm}^zh%j(p z#96rMWV7@Ig3?ONld-X=HoUJm1JhqbDw^Y&*4Ctj64(}WwYN&t>)a(O5c=Bpu3Kf~LJUR6zTnu#5Mw>j1LI{OJeJhl zwI<2>k>9lJQSHs*HtGFY@~Z^d@9Ofh6!BC{qonz3qKEQn8;|QYp7pTU4;m)b{j-Pz&AR1X!DTr2z$GPHoLtak%!lh2HhOErnQUP|m ze-&>#kRAPBskV?U7DAiy-zYC!bbHz&ffdKl8W8<%1b3oI?c1VAtn9RFS@xz67%S>C zPV|dTg^y#PDIG&f`81{t*O+C{m|jgNDSX54yZgDkpCacHx$E_&h|1Z@c1hKt=tjsW zCcz)eH^9aD1nogm1h>CZN`!Hx^a8l2Z8b`F+I37LERXP`GMG;Wc#b6s(4F2usmWdD zwLYh->9yomfn|VpPDyYjAx%)7BK1CT@<{Y_f2jD~uL|vFo$O$$5SG9;I$gGXlOQCh z9`6}xFm|Y0O=4RTby%$YUD zTVeT<&oLg}6pPhG!4-yTR$&Qmk?P&-hVEaLr4oztNNTN>tYEM84#mQ)EK;wIjQvY3 ziTEDe0MDB;ZQskFT`%kUIides=n0TC(C+@J9?!4i3gH5nz zH6zTTWmB+43=W<7Q4fx%Mo8F4$XM^YH5H?zQ4>Q`w^H}Re8PO^h_pByeAG>cfU(n| zL=+$B$bzMO$K8c?Aav%y^1IfJ&@wEzE*9&Z6f&d5oASoi&znXV|HJqc-Uc##RfQ*A zald-M`e8i<@Tp;4qflCY@>NxG%LBy{+psPt$2XJj!4pn~(bACa)qB)+uL+6@zoN%{ z3?X)z3KC*$QfkDFhEw4Ws!E(2VY-15Y5vTZz;|1>=)BX0j6)Y4q%GK+6ar5i^mevd zhobzCpfy)bXypN4B0K(M8PtKpay1}!#qSGiDvN>*jqlO40aLxsx zTq0I!EpvZv&|qGt;gjEqHuMYEtnZ~D88hD?wnfc3Rl5aBrWf*AQ%=@pCY(zQ6jpV_ zeikXv00luA8fg2(XdqoT3I{9*VH?#@Vr!;fae8{fV3Eb1}V0(gZ z%;EKSDsA_H-i=%lFnZQZRIG%UYvtA*3Ho<0U4LwOqM-J(hjr42^&@Mat6qkLzilxd zHda$1k}t~AuxeVLv=`|XEWY6Hic{j+*oo9=ZlV2=j7si0RJ`#RiB|>7!^S39T(D`m zBOrFMkXsH=PCkF3JbvQ1K)a`;I=KqYvNIo>HyR*7SZn;F#OmZH>3-Cs!yJgBBDwk=>eoUSOqQmjSSfTdVROnNWlZT@rIhk%xG&`i|Fy zZvV>HB+Q_=3P}jR{e!?NkFh~KhaST#{cuAQJHe2hhfBP90v*3G~{dG(^WzVB= zNK4XHiV=3IM($=y>uDLYeApD}Ld<&dEDtI?g62bea($HYy; zSx^=j5#GAi%$}3%Xn<&bLp$r4!lyC*q(BC?)=NI;W2+HBylg@!jQ4m?)lK7(lB}6N z2=?u|rvV4Kw4A*dKr)zRgkBDxd)O9BpehN_V=N?j$W2|tScQv_OLHTxQgb0dyu8F# zS)&aU#o~iF7tYCtd2~`uo-w1ht_S4m%4MnF*RaO%+a)ndGgkBi0c+UdoV-Hw2pugIiJ_5&z&A&G^C4vLuBIe2hud}Oq2r=^7Y9Tvyj}G}h;aB4qsI?z1E-;pFxVjF$K*fY-BJSNY9ab( zm%HH22@MIZ7~^=ZA(uy``@pf%x+h1c%2)$Gg7c?YtXdG zVwwpY!BOU{HNceK2xOJ8T&aU_Lt${0ozxxMMsr#rO6=8i5sdwXDF?a&bv~u^TCJCN zBvlord{g4&Gs5TtCL`>`z67hl9!VP?+nZ0M(p=C=U969qacwntJ~7b~a%f3ncc{0! zM$nE|$kMh)7cWM!NPQ@+e`$qCopB}_ z`5Q+#LQ)oGyxY}O?jgJ|>G#%GnMyjY!s#J2M?QcC<3_+{I`-|uRg<6L0{ZY^h6nqE zAPYf8!u}C_7HO@xh|3DlGnmnwO`Q|@h@kKgIxdS%&4rVqo5oaZ+b-!>tsOVYpajJV z)rC@9)~S2{esuJ(XbjlBN@KB-Ego2S3LRZ0(^!3X(LQO-MyVV1B?XeEFp$$LG>c;$ zg&!xGzjVe3gb0b)8_KmJTRxwQ@sTMfjjG0@J-9DEIkV)c(m4M>|Ao+NYW3I(qJ;-% zcC+|d{&}wxoDiSS+(c!TjKFPlxR!3xsXFeo)AT4U=kj@LjW#ZstgAS?iX3p(VV@c% z%4<2);WG;$Fc4Z?p@|b@>JXM)mL8nkK^m^n^K55F=`2C-$rJ=dhN6}5uGXsCof%M; z+3vwikNRdPX_}qh8i7A;v(P=k=0CxbTFcU@$6RJKvU3oDAjAg`d4m8MMu3n1tL-?d zx+ccYcyc-Vlz*oOo=t@|I_{dCvH(`yqJn@UEqyt$$J{$c*Ud5K1V{&F4~2Hh`dfu~ z03q#-(d$~()ReAlVz$V-2m6yMR4*FoCAC;mzA#ct;d(9d{gjiPIP3-hrQn!Xx6xk; z%?8nnYy@N_S5n}#Lo^3&xt%`JNvjNdTP2F^C_=}0s3t&($$~nvt;(fLBstGP5bpur zkB-YHY_yy-YIe{<3ZR;1*iA?imRDC%LaH7(FT*%qo9%df_+YBqqAr6P91w|2w4gJ> zl&S=-D$sxGmi{fITHg}WQ(Fp9%Ubx$EVE<)*sdAT(oGG4&a^#A^~EBAP}XqaD6a(w z7=NJeSNgJ(3DYy*68t2oDVG!(LW1wNb9onRoQ=UfVEX*=5;pL!Q5&$HUt-2dGEc$5 z188dNpvNR*!z7=<;#o0Ow)=8m$>_9}d!ao6_Or{A(LO>$iir#awE?SY1J`M#!>40$ z)2FCRpjRjhlWzKDSeU}9e7qJT{iakgKj4XSwKGwPDLfs5PL8Cz?G)MZIGT*DY+5k< zvV`N%w|#YL7`-(e4q)@9?!1Bw-hKEf)+oO=y7G6vW5Ru8q=8{ZMub6QLQmDIAl)Cg zLK<`>419>-=TZjBY4E256`aV3d{|v<6rPIF4@xegWJCz(*RCewSno{ zm9T%b2XOKf=NYr(_2RvCC6kPIkX;V!%;Qj9wPK@$ZeXR9IMrthZSb0 zE1=Y>c6n2U0#Ow6dZtGEZ~1R1>+*w8O6*rz^HNbTrE#Gs>MCcbuCGaz`drZY z`18i({BnJiO@aQxb_%@1a~!GujQx7>6$KL%qqQa7ReH91It?Q+Gu(veAl-{-5R0R zh$(}tMCi8#TG0SJa!$%(r-+y!`HA4XbL-xUUcd2Cx&0^HGU*zhP9&zYSTFnJUtl{G zCYqYx*lhr+NVQV;2ib`!1v^e1KXy1P8Av%`L~Y&BFo-2&AJN+~^@{rXUXW+|=m;p%iH=*l;KxkP?Vw68Edv2~Bd6ln026O|!%4HQB zSsLk{ZF!|0-YYeb7m%Q=agnSz(YOJu+9Q&8^nF;7EcSzY=}8a-+Rv+D7uMca;JIhO zQe!u`qo)3a!$cK9Mtb}a{D(>gsnW}| zKtlL>g9g;b{0uixpSNkxxu1~l@e7eWEHK98iLkxkXi|TUJK07gZ7c)6bR}n_xBpU~ zd4&k=IXi4dk0}M5!WSBCOo=(CWNT>vd1I#e9Rc&t3re#z^Fh`RafWme^hFlun;;t%xS& z%<<&h7*Fry#mu!*?ARlC9&jDjyE0M(_wRf!5Tb|7AaqALC6R;r~uto>=#^W*$5t7?y606g&E-wO6= za<*c_wQ1>osK~VWkq0ohntoh-XEO&XU~Vop)j1T!?n^a9TQIuKCaj+mI?56|K_b>M zyP)Vk8uxFR0_8mBhG>Auw9gO&F5tQ21aDSpLryv85)nPh%mT1T;SkxHxv+L9N2Kzr zuG@Kd$Eo0d$|VB9Ns95Jfx)&XIXePv&l4dk}yy>mmR4gEdSqZ317HJ7|!C z!k$D1L3`@>yCQn5<2y{ajJh8Kz z{pnUh%kr@rQL6?TS;@qusG)fHdL3qZI=)P&W6{NXus!%Dg<1;}(U-Q2lpQHw=5T(YS;PI%bwGVc-tDt_acupqA;h>* z^1Kq^A@e~hgn`lY_;;dt*q$=jdumB&y0kM}A}M~Q!RrP_kniB^w^q+=Y&vZZbz#k) zp`-yL-0A)W61EF4jw*!66w0_$*YH9A5gZtqtgUe zv#l?2#YNdQy|O@AAnp1|G(&^7GtOJgWwY)c%(`4vekJq;mI@eh#^|tqpq;iD2+GwS)x36 z6l8)p^G@&>-H+}n%dz@PbeB^!K81NfHe9Blru`{4n1h4yEm?Qr^QNf*yKN3i#GQ6Hg0B#rRD zyO=TcR9a-$@AV*yG3|w)f;$pF{w0+ zmSVaiOK+IPK5~Y!mPhH&)+{;TbTG1-^k%>Zf=`GQWt?QAeCf(rGSIJbI!V=reYq$x zu+YnB$W>WH(nC4Z#>^sxzh^7ByXZMaO`s1QE=bCG)r-Sz)$yxNVuKfjCW49DxDaJv z2(wZ8^u@l+gw|Ks4Gf7o1tg*As@6B`{FTO5=t3LtB(Va2`;Eqy~6R5lkgeE|^uk!J|g`j9UIpa3C2-oF}X^5AyN zs>E9nbAjE(F6}VS_>dfzhGy}V@!2sVC3yIEPm1oSvZ;%td|4{@_gJ=7b3q+&Y(8grI8c$@ z&zj2m(*4fUp<@LI8NVL%yD0KCL306~qZfD+bEj&$5+eT>>7ursrGjIe@Z6GPxm>MX zuI8nksYpQyz_S}64oCh`MmQ|@5p&Ns<{tQTC*}y0@AVt-i0c&CBXws%-6!tbZlN91 zN%=WbI5nU_r9lKO|@GCr_!kGye- zda$XDqPNpO_iO8Ly@K8w9xs^d5%Q?gV~ze zzYQ%?vJikulyR5DM7)$^iAamUqfxm$3{?#$;7nfhY#rG!(!~&$4U(PXA9Zwa*+(P$ z7vB>#Ylm>cf@E|#8rcz*WPc=IYaFEUl$RnAbN^;u5}CmBV*J09MhY@B0O)xAs9&pY z=^pK#MJ7BDXI!EuavlJ1P2AnANmAk4ugphP+eW!aoOX^~dT`}QZX;kf)#92FQ{VZm za4)YIQ1prnMCEN%(?6_T50+Y-SiY9Oazfj@3K?ba-%uuGWAzA77KcIGit43UiEtT- zGw7L=X2|#UVWd2mnt5I|_1$)fIvmA^vZ&6?a%RclFH~-3$;KZ~hp~oT&)JQ^2^53t zbIYA4>xCa)XgG-fA`8Nbv+`|RY5613j2ZQV#Y>Atb1_0k%&_CiI$am|4Ziu=I1%Ch;u1G{k_ue_8Q1Ku1zs>-%mXC>;h?K^QjgLTn|Xo!hH_Wt>EU^iADLSU2kJs zQ6d=n_FR2IZ`daxipf&z4)!O6-D_R95TjKxlDji3=yZ75hkEFk zp8Zgi_`MVoi*<_pYLzw=Lwp8kXs9oer^~$T|F?23zo7W1^mr9y>4C}O2@a+F7b1{6 z*`UZm`mB&r@!LW>IJU@%qsF7{_=9=F)<+_;+1VzFSOCHQc_aqx4Rj;HTbNw~3b#Ol z?tfU#mfS?8RY>^GTP!>HyB%%rn^x`tr!};sGci?@sP5Kdl$JC84+L|Zg&2u&wO_H} z41z&8&K-^2MYHzi$pn@x*nM{?3z!{Ge^1cJ^j^7+Xr~JkEvlldSERkl1**2KRio}B zUIZ2ak@JPPtMAiyLHOynS|FZScBbZ_6Q69LC#l(+|%G_s9evx?Clq`{!A% z^BLtqlQTvdnX&`2rE};t*j{`tc}(j41vLU-RyktAEb{+}J2x^z|933Q4MSj=e!Ck! z=bd}y=HGq$eBX*SApO{u?sIf&=_2j?m z#l(cTqaEnD``y7TbCURijk&fi+% zFR_KdB{QFs`-D3sY%`oSkarb83tSp=V4du9@4i~$E&P8j%wg_jlk-pJAB`M0E{dkk z@D@fF#95S(v&kVomWc+U0*|eLeXH#%=;6m3Q6iuQy^ZAU93xI z4J-=R>SLQf?p+SKU+RA3zo8K)skyjfa8~E%$2N6Aa8NUE!;1^4CNWS@7tzv z-?r3)t+SU7o`H#MjwnA{-*J%n=jtVwfN*re5GE*}ws25d&@B_9aNXN`IDIqdVZih_ z5B~Uv%{_TLlLI@;Psqz{6L}SJT8Ee;h?511Y&{(wdG31Q{n<1oMxCE!NDBNiO<%?H zbKna4`Jl2&3?8iDrEufxr-sk{daospIoQ#++t;lf)Z96p)bl zR2*QfhsiyAbvg;;YmDLT>-8j#Ccz8JR61U9!z1xWR^l94P~P4eqNSCf*MlDc%@UjcMqT|*(u zH#&tA<@w{`dXCGlURcU2u+E`A0XTyVml5J^2JcSSWz3D)pIP3BkP{Od32%LcMHv4d zYhjiVUWMIhk**k#r_-?~NLTFBitQn-xXw^YpY*7QrVTKiXshse{LGJKP1|k#JM%1= z#KRteK7=>mT4Z(|GJ^_E#7>4j263!U5IG{rBGQJwTh5o8sr#qOW+x64rGtM`LxuZ> zKHm{(bc;~*>MVDITRP8t+u}8y4Y|e!>@Gj3W0T|MF)ryx&1l<%`>B%rFH5V zG=Q%E>DI|Mb_+oeLU}h^8gw?c8>}>zcNH+Bow(TjsS|ZfYD%U&Yfi3G~GNgkB7Oin97^Al>QNF@SP(^W1*dX}6R*GqB^@8TC_^*=SwnP8 zIvnc>W~lze&$jinfNB%UM3ZY_WR9f(No9IgUD&yf>Ku_~FD>3CFO{%`8R#ftU=Cls z;eWIohQc-<#|i6zU)o}q+FWvX`S0z7A~2YJ6ccO)Hl>}F7=FGKw0kl2n;AM+G0XEV zvgOT&-R0N*sCN}6`O_j1{Pcp*bT={K@EVjTH`QPCQh^~I{XNMW3Ju}Y$be0V$_1q1 zBjaZI_hz#0hE>|pjGU8~;p+j*1a&L|35d6{7NC_$?;efsVzqYoLxr|zE0H6SqMmhV zWY#g%D7(3WTQe+yjs?{@D``Ud+MtoY_3>+i-c(=|;^5={ zvs^2h(ymuRwp;yKplvqwOFWib5%tJzT`$!aUcq>MX$eHneXF1$2YSQ8 zfRFKzT2H5=(xM-(&m(Ng+kr(1{I>0%u%a~170+-c~PG#Bs{?>2A6a4qRW~$jonx`k5ZHnVW(SabYPW|^(}r= z{gWUXQj7z^`?B<%4$+OhgeRp^$B0ms4`6; zX&?CO1!Uf~Yx;D^OCix8m22oFgvCi%kKa)k9JUW+Y`K2RnQg2Or~~n97l4}o@jPlK z9zke+HA-A>V>xwit_tKcR*T;w|1U?#P8Qd$JYql@=5r7Ews>Dj^%G>P=t|){Y4ovA zgWu?)lSWQ~@fZmWldl~f|A84|wSP$fu8e2%&JvNUr)1m0>~&MYV*u@1jgvfl`R_;l zFwk9wX1hYNyx5Xb3<&&?OSs%+()PFzp*y{q*hc~&LG>*aB!jKS7?nA$hUmd_t6hHy zhvwrs->+3V_W<+SQ6s`D2=|E%$xT=tqB1uNEYfus>s}KzU)^M3?7A4!{X0oxcA&8e zQ!m3+2785CXm7{ZswpLEwZpBa<}v|8Akk?824oBLCDoiF=3mv^Y4db)R2l7wC$nvL zUi^0io*Ge+lsj24?P(KwvBYnLFmw8DEBEw=&&hlSSPA|KcnFU&>2STRk^>Gv-dLH` zv5a#5c*AiL(82z!3Y!edMAh&cXlaJIHv3KA@b&z2B|LvLNz(CU(H+p(_#S2>0G|t- z%R`!0U)nFcia^JK@`hn83>`NSZJ+Et?F}6*nLAh* zJ0m&jFokq;hWa|8nwO(2iU_7tE$hB3)-AT*Jgs3`x2E6v_J{UP(>YNM*$)toSbk_qnRCX22n{0UPo> z)bj%ioXP;=a7y`S`Y}vL|s< zk%X7E@j4VG8~iPJ=bI*t8jx@q&YsW05XlQ?P#|uCA$&b;*DtEg2KaFa?ug$2eqUa= zS5R^a4?)Uxwk3rY_)$a{jnq-tkOee^3u+jcX3#Pn+0`elMpdBwJNyaev@I|lXA8Aw zv{?a%s0k`%^3EVNhv;qX2B2~(SUi|vKSd(t*T&skt<%1s;g4V=dvwa{vP$^~LLn-g~xWN!h z-eX7+NFg}tN-3u+@6odHjC$Q!yqv>=FIEH)933NCHGFO&Z zO`j|=am4b1d*&b0?4hOXo$L33o5QQ`}RYj(53Mn6jJ zg>p39mZjpMR$}v=$DVo%LM_o8@bAX&#>SdeQT`8Zy-re*kb5Gr5@$Liqx9mkDvhL{ zO#U#pNW=zpP)PWq)HH1a5(Ab~ncCuz6we zRA9}swglU=k*(5(hJwA!%G*{FZ;)xyZ9{6xN!o|=ch@Psh@?pzMr2dF_iO;j=s!&D1FoMq}=ucGuNCfDuS6@lH*WY?(LA>!)?q)wpQD+I%o z@LO%jkA|ajneol1cKGJvx3IC&h!iFt&>N}j_wauh^c0P|3X_Uks(;sClLaaJp|%k% z1QryMfr|w@QMgLIFD~Qr30d4ZlWW_u&gfBRv+Ot{^c)@D=3o%e4fj}3Nvfkyr#Rr? zavq6A6?3imiPZox2mfbjWW4OD4<0^^Ll5I8{=2CDxA^OR!KdAn#ECX5T5@{_bJqnV z^qcUyyKx2tE4|NsL8QwkreqDEKb%rij3xNj({3hqy77)9nV6^>kSfox@Is6^98kkU z`BWZBRoVC!Ib-2o7YRWVo#Lah`}|rv#%-Y79+!(vk5b~$J)FM?WsuglVDr@lonLGg zBN+O+7WVEXFCEyIb!!fns92=Xa6AO)tP^h&fo?@M+?Xh0Jib)*id%thE}i{apQO+^ zgmYod;|+C2^ZsgSAdUcj!F*vQu}3^A;5+&8r#)VWTH4vS_VS4&X7K~m{>LcY0&QdR z_v>ztf8A~n_7}3W5Swb{tidvUD-~-0!%zEW%a~leEcM(Cn$S?ORPvl zxKc~FWDDl}Fb}z!0mP$wI|;{WGZ2a-zTUwci}ey!4|ubUnUaJgCy%$>pXbabJIB)d zLaw5eCTP!T4~mm;S<_lOG8XH4SNj2QE=?h3pJ)MQU{d$OH|hP%HOo9v%`!YhF6qJc zCgjR&T*qpFeYO9#y9o}C1ZM!p)W);*5stt3@eAQhO~n{z{uvZmCY@Md;IYmGaHrK5 z)ICJfYS|9bUrX(4sJ+w{uwvA)|C@r%oZYV0{=8@=IroegD)C7@xHByq8@cj&-pVzkOaz zGV!HrB+igoQC9ykBikJxgi80RzleFQeR+UdSuqp)%O+fdudwM04bsC%&!Df(9&q+M zmXLH^`PD<<%4}K2RykX+!4P?__5)I)|0E{3dL!N3ghPqHari>RwaMtXzSeBtN8%+l z^XPXg@oa~L5CCA3p=b-k>{8)VHtP5PBB>t%726l?zoI9qm-IguuDiEwA=rWC6vh$R ze0PtcMtjLRX5jSHvbDlVKZ^de_fEYhAyol^rfoqQc5Rg-5i;nYm9;hDSLL9Ofx5Kk zk3G?l5dqyg{F|?{H_xP3cl&WmO%mq=`C@m9y)I;60CzVdD>(O{#wRX02%y(orI3Ke z`53-@NQCa;a!^pf_YjgJoi#6U7b2`pzN`IJZT!c1@1Evy^b;Xt6~^N-kTI2N!!OVN zS@xXzQE~?y)<+^~NKJr}dboT#RD=s1F(;{T`Qp%dU7{Kts(*etN2yo0$&-999%~9g z%bB}Eb!8az%EQ5g&4x-dZ_s@OEk>3Rpl#+EGFt2d6ckU;&^!@9)X=I!?*v(IXBccM z!9m^W*r4_Q1d{Hgj;O0%VTICh<;ZOP25voGOu^tonn{CTVbQ){#qoZeGB*(qc^&Rx z|0!WkNpyA7Ic`W&?2t0fd#N<0cPp|Y1%05ei|)5V!8gyl*+Mr8^a(X{(XF%%#q0z- zt1-Ww(om5t8wEl7N&B^w&+#G8i^`yi3Z1t%rd>hGZt=o=0e_DaDNNr?dt6slpdM0qQ5j%yj+!VPi)912KXroJG$|vC4hyxx zhqCc5&BZky`g00utN^4;5)NSqC3uqWA~>AWcd@<=6im`%zi zf>IC}!A<}D`(bjhssLc0q=G=8QGR%9_H;qk(P68$l(c0(NU z-hNTzvdxu_Zdgjxi@)XGbaga2w|#W+6KICsZ#IC;CD+V+(E0{iuLB>D^R=K8D>;+b z>-8YIPq075q+yx~Rn0Y}!i43MG1sEk%ZJQ9HiUDaz_Nro_@QRv3V?y})~kwxP_odQ z)Bh1?iyvDJa5BgJzQN9g?XyPA?2e;iU0{>S3Em)y&$njrsk{0qmgxSdmanCH_UhpR zv|{I8?8L4K_@HgkxdK2~8<1CuG zNCbD{VM}655{OXV?8huzn4zk}maJNA;d2#LPn5%NbEL1Z>=x3OEYcE6dS(hKg=Qix zXlZ#;(zbD0-~FjNQ`FD|(vw^v(yee)5vjZ=O7$h4IgsO6*ZncxAA}a6WLOqx_fG-2 z$o?2mt>-`*pr#Wz8ad%7ZIG-`oeP+HfCJeehV4AL>UsExu0}()L!O|ZA2UIcu!{;EOuA;%b*Ha65iThHvVPhYBY)m=gmbM~xu0|F}F>v8Bb#1Oxpv z#DDh-HTXko!^O>+;U5>hK{(0CmoFS%3TQxTIQVp4eRqWKqG)vw!Kac6$$Lj|93ApB zlGmCj2}uFE=SP=lfTgPi_urMJ+ACB&>2waskYQv_edO8uP96}$dI<;j@(gh$XnZk+ z)&brKNVw{CYH}-3j6iyw1ABCs7bHAYr!HlHHPdt%$aZ>zjf@zn1pOsWX1H$|Ir&If zbc*W;8h}DQ4a42%Q9=^ZVw92VtGzgG$O}0Bwo7agk4%bh^?{X`Y@gRUCMa}P_ec!Z7}O~@7}xyW#l*>BHg?b=n?o) zcJ~P3pDT33|AS%-kXQvxopEr$Cac#+?AU9)usJ=B~UdH zo#3J8j__fC5oQ5)`n^55mpZShRx6EMF`JoviQC>l&r_g#C>T`jPONVz91OmOyuOMT zqT|t&w)=^WG92XWY_NdFI5`CKw|IE-HdwG_(k%-ue%h?6CjUJe(k)TUi+VVlblLe< zvzp$_q0BkE;K5=eR=@o&4IuzuIb~+|kkSII5t<^br>P23H|R-i>H-0xBKJ=Ij%(4z z(U@;qBRWb2JB3OR64|%3QR}p%uhP6RUMfTkYhGC~YRZp~)m!mfENVBab`07Y#&O&L zMojJSg2&8A3{$W{P@>T?cB(F5!} zMAj2GOo3P_XfxC_Rcf>3HghBr1_Uy_=P8W}=kmnLNu8LT#i$qys3ba!hG&?|ztU2< z;n?@P#S6#iiTl(p zxCRv93PFE;0icph@TaJ_LggXXU)OD&d2c*HP{#lc4@fh;??HTr!Ax;3`R3hD=w7T; zDAEE~9hF2P-4>*AD9GPEd|C|zz4BRar_?QE_x9qO6 zy%5Q_^FV8L3l$E6pCH+wEqh4n>Eqdd8Bl%Ir*D*{bYcehGUCL`^c0j? zd_(RE+}x@K4H&J;#-Dnv+{Fz$H&h#if*s1xo^1Y@58H!1nD6HMc6V?R7h++)++lEhp1FI09zEe5x=rkFzwn#sFb3Iu=q0C8+io0v*9DXke*MRUddy1=X2?!UO z*z`S*4`Jq7e!)j=2ZiG5(2RzYLtfQ@(tl} zv{2&gD{KW@SGLx&UCGPx@RVA%crrJ90{u9^v;#U!yZ8&Ku4cHyt!GP0j~~TUa_DfE z%@jv$As>cc?I#PnQLR#Wlt&cva-?@+gtbQ6y*K(qQ?$-Yq?zVOEj7Qgp1@(eM#)Bt^j3rAlJJ3SP9}Ay0&vm2bAY+bdN&F|RPll6`y z{x1g$JsjW4JD)V>jw|nb$FIip)xHrFg z$`$T}FPAN9uJU?uBKXRSkR7^~ z53sPqH6NhbKvUIKm0U;v30+~9EgQc< z5)RMMJ}?^UI#U8gxTPgCL6m*vYs_cn7p_f*O?}F1GDD+F9F5ooZ*>0F=Sn=8>GqNP z9!&B4YqDvCQe20}e#QbsW3T6T5L{w3J^IPHos=M{Z*$SXrV|Fic;&k2ffg^{P^r^( zYUjsVt(PCUDUKpQQ%9MNai>@+P*;Q~7^0SiNEM1d=-Se}M-YB6%9#L0TQqy`_V$!T zQg4X^Vtqtxh_?lkq(MjR^Q2EBtG|58I!*>PQ?(~Nog~)$1^5J3dWT=j1SV>b^1RjqXBrN~ zH|qprHsH|s-}P>AVF4JiCABdkPUq&fliw}&G!f>vV-FOQYHEM3*Q zo0N*#1Tj}!i}jpVqx*hbA(9h0-E_g&4Nz|824=m$NvKnav0}Q0X=fE+8hn2+)kO|y z-i+8-n%oF>3E@UVD}hg+!fm3v0K4a_?p%}Vk=nVrd|WzaGnhIY_pZx$gh*hSaFLPM zZ@@vqewi>8)RNB2n;SQ*kAh4)t;)R$YkaA*+wp&*30GF%K$^gAcjo&VX~XZzuG`s? zijIfiXX*K`g^@*nEKaOBgEEo`Dde~7I-d!^{06yb#luf8D(&3ARt5d2rCUi_*p=aj z&Cw0pfR19=L7WS>Gegr&(wMrmbh64GqTzg8`^2Jfr1j*sT4X5Z4JxkkeExh#)d zfJZvQFR?$!Hhi|+r1x7f0cp-@f*(;d-onyx+|clBrF+N-T@=YTi1@ucVyRqnxzi5NhEF>XDoMf$U(1I546g|D*Zl8Di z1?mNgt7zLRFnxBgpAm?H=0AYHJvK_irZzAq)A7DwMbk5h@^PICtkA&MBi*b1b+cr? zfky=`9w|?NY=*Rrp&{zdQ+g-}qNQv<<+NE7RS#yyB=SW#@R!8jbYxd6k@DPYeW};| zJHPdC+Z2XHw4`MHI%aJ1smxxoGImXcj|~s0JSdGxBTpFuAgb226r~l3nQ5pjA3Hn~ zvvem=z*=Qi@5`p^D5B#g^Wb9mDpZt9FtzeRmJgGXZq1rl6*bd;fDovX4`nvwn4*3(Fy=;`Z9 zV_X+{Qr+mv2_>+m1A_2Hva!zmYDRA3@kVkb0grYlk|a`x7cDqB5c4RzIt=_48N`h$To184_*MdslSp(}8&KCc+)q3=$J z`+0L3rc?D<63cWfve;W~c5UA{ui8)PJ(X`IL*BeO>Q8=vuqZyDcY3)$dwnyi+rQ16 z1$C|}Ux2WDP!=qoratSNFpHSG3g;q#ECNcvP5g;}NyfnNXJnbW&@L6_bdIhZuT=Q3 z?3VfWd(bA46ynY$7=g4c_UD}*?I#A*=#)s?ngQi#VK)8TRQ&TBn?m+AFyTGN2JPD| zu<<+GHgjKSuHCUJQolr~Js+Zvdg}dn0f+cf(T5h~41!%xQ2z;N=~i)9f5Y;oM?&Ao zf`MC0ugRlyXgdI8>E1yneR50%>v*ON3-=f@l~k}DNDs2ZhjC>TmIC3Gf2d(0gTPA& zES}39aAt_#W&RM;ghiz~a31*UI~l$$>a|Hm_eg)kyO-PpAgu~U#hJN>aq)zI- zzE9R8$fdCX{hHLH%p(-JCeb|VxPmukx_%fu03Pb4w({!4LOn<6dH8PjfIFg@G#Ceu zopy~nv-P*>_&FhBMBIXH^YLL3p)QT5;UJTr^n}DOG3U5IFMb;&mLO2WLFh7m(GYfX zRS+)|@V16Q5)`t>7=YhuF1X-v!Ap9oy?f9nam}7!jV4O2u?7aineHT}w`v0yd{?y; z?tx?M!F7$u^s*Z1*Nn<@EQH&?JIR~0rK&ce8{fstNZDr0pR*!R3tMvt7z1Z^qtaIL zYE36q`4Lmd-TLcLiPGy1;;r+tkF`#0!i5WL!fYurCG<6L6PtP@zO8ZVOJ)CXg0WjUY`$l6Wb?)o6SbBqVQV|110$|e6|LULGJqXRcR zdfV;dc!~E=@3=Q}vPGMd6j~byIgShpbz}tp{Y@YGI?*b_E74wPdg|E5GvbuZzq755 z5q_f>Ps4!=2U`4KVzXNij(k~EP{=wghcS8CGHnoeFGrt0fyBDL2=?w&O7dngNZL}* zd$6BXd+#UnHkZ)#2h& zBPbxI;f_$+c#MNf8_Zure~%?SWw~C2yGjZ16xUQ>38VruPD-F#^5)#Y5!my`A&mLQ zbg)aaqMh?9zc0zTxPnIG=Alaff|(sJ3Gr=1Nd3n8CbI)-&g*+9T)=QxJ)TAhAUv^4 zBN}Zfj`)eN%g|fX`C0R)pi7!rQp?SooA~~^`=HHV%{^C(^a6P*MJXnxR8S=m7*Xp5?`BELf!Y$LvcV7{EiUx6`npK?6Kv z1rG>8)#5uNb zqb{B{moRP%8DuqsY8|x3i6|?~a$gwkyLVB?VO^%W3v70nx(TA(afuY|a}kbbh1_nA zA8b8jJZLBTuw575Sg-!}KS4$pCxi&c(o?Z?6zMtGxLB8Nb6402fJr1#x0O?4RYTaw zSvNU(j`c^kH^X|~N!t4|N}(LimG3f=oDuQ-wt(@JokL!zx;T z9~Kox3|zEO_VOs)uBvm&4W{PzU^9V)xuf<>4sF4nHL>c0CHVogB2?uWu&caurr?O# zb%?0dUW&^z`cbVjFbd#YBgC4ri5)qXF7LVQy(X_*F0@U%!8n8k&Vgbi%d&%ulgGbd z*FEWkVFC{fRVR|ha-b?=h`z*G#is0AGxa)uz3Nv9?9QkAdbez@>7CJbWIELBf``<9A>NukN2IX|^wE1Se>RK|s5G&$7%CtFd05C3A!=z5jDD&xhhd=^GVn#j^gi{ya?(>DsLpR=wGSiGbij zN6d&-Ci{*|I6e}s4FFg^;UR&S3ln`Lxi1|01~YdQP!QWNX5KO*dDNcrH_PiOjdOAZ zLfot}`LFe&8w+L7ozwtY))UMc-R6Wu9$o5pFgzYe9_PGVWHjcQG#ezKu0P80b0-skPye!tq9G$UYAhj{YS=w@6a#?bEM#D%E--&~Ole3xY zP<;`Ky$pVfd0t*`4dhBKa!9g7&qn$|QyJ#^^17+> z+ODCL`9x+^CEI=Z20K@&TNk>2wVcJ3=}s`7#Tq%oF)=LOk_1w5Gr9w3otZIfQP-x& z+kzq+H6Dn;_NYx%MFVh@X01I?vboF@IS~dxBf0?SLd6!3(V%lCrtIyWY+NJ{aSlnV zp$2Q$s-3%JOT^s|cJY%7+nhmP(&N%KUH|^zJXG34;l$n|r|Wu4HKh@VNg05u!Gu1T zn+uihE!2UFPZlnR?rTYFj4{dd1PWZp?rEx6u!`te@xAaNK9h>%@66Jq82rV9jtatC@3#1%2Qs3VtZY~k(!iAqK;ywqBnAQb@JOD)X|`diu7 zTi_YrWr4bTFGzHM*r+nYv$qw?TN+4*{L1@q;>m*)HaDY-jLy6YK*GK%->vC@%I9uN zw`VP~c;dMD%JQX4HBsfb5i{q)18*f8;Tq}`NZv&6A^8^JV_ZucJ-7D+(t``XTJEdR z4b7?*JoH}~_z*G0wJp09Sf4QgB#WaKrB}Vs^YJI7bPwM)t1TRFfvmIi6pHPBHL`1S zEqfZd6s;r%*i19cWlyb~4MK~33fuoSDi^1MHV>p!8&dz>3d3DEgz}GT7_T7iDu;+G zMw*F|rK6zM0ZYH;xR1%58$f(JhEoq-8DEE*8*w%8Snv>rKp=M9= zjt-vLQ2mbCtnbG3rSS7H`>V^@Z6bqJp2iDiRD|c6PZD{e*kIo?7vZ-nakLr4rh?}8 ztkS7YK2T==kB_%BsNVg8rRreK54Mqs;$RSWtA=Qz!kFnah4VKK@VMpALEW}KMMV1` ztTnWgcMaPToRvS%a6V!SO3*d_W0Y?#Nqh^qZv8ry#C-#(>G2NQq3UqXFnGn*9o?Kx zinb&Uyn>p1MtQxoX{E8E#P9IlRX3C}sliU>!WUd<>Cb zYUxSOm-;oV_g1)g#UZ(-^SxG}vO9-MsNM0Y1F)EU2Y54=xP^7&*WJ_oIfzWRudNIq zo9uX=Gt6nS^BsA1m?-HP3pb)B@Qxm@$v^1DYwH%ad*V%;5Gw&z7#`Ur_1uGW(>3kK zoz|`!V)r}XNi)BEQE=IvgIvdIIC}O9P?d4Ik75A%aTfOVv@#%G?e#v*e(`ZitZXPI zW_i*vylk!4>YiCaZt{%MG2dGMQ3;(sl(iV{%^9Tt7Wca`dh0w`;GqF{N=3sL8@{e8 z*F3X+GYc}Y44ViNx(8g8v*Oo-DN8~#ttT$GRfL4_=MK8ldz`&BuY}%0UxV5u9;)En zQ*&8RAzf4{R&|_;L3#T^tXVeVqW(ie7wSHQUq(zYPv_(~-%BLs{ESE!qN1WYTGTzqNgG16-JWp>#_ZwU z)&>unv(an1l;agPG|u!&yDg~spGJ^G8_8F9OPqg#XkDLUL0}Nta9bD{m`TvACD>F(al4>r5)3cnq#`^+z@5Xu3|MiA98V zKl<7uG2Ez=4R<48P>o2~ll7ylYRBU^uJW;K8*} zj6G(>c7`mob9M^kL$FQBeG&TKOYsMb6FGD%L_?U{FUI)h5JEcl zFa&kmNx8+YM!)*1J9RjIxLWTEgwF2&R#zCVL-Z3UTv=zfVM}CDPWy7Q3)aVwJqXTv zNH}fHgnhj#;xS$&r|Mf1!F^FM4vk#jTzuKi2`Ur*xJpLZjlGPsvqnHhc}*GE{_Ua_ z5_O7U87FaYhWzSlv*X3Xg`u@A z(sjR?JFnEy2qD3}-x>ciu~suBkPw6z)4RSuY^0pLdK38zErf)hEtOalKV6?(Rb@vc zgSCSch^@d_2WbxA>kL-z5Ie@Pyb$!SoyJGWjdd+J#;OSwPQ_?t_oRgv7VlQS#`rR( ztMHbBF$TYWEBS7c|}zNTQPRUhd*EHBQp38r+fF)Kf?o z@rSVO=k_zPngA*EKi`PnQpDZxL!qtLH&WsbQg4BQg&6N*z4@|Ofoi!G9-J$q81QH@ zMpZ)b5gH5nB82&MPqgpO6Uc*}u1y?5pxt5;dick#6C_Sx0-hK~|Ql z7#yK|r%kLiUc-wD;A8~8kg0a1l#+9SH^036giDuP%%eD9tvh{j zuI&XCHEj#eSCcm?WWGm3Khni<2mgg^CtMYUH6j_(QK`*G+JPNTd6Up>FvN+L8GrOV z55)XIP7EIcmetQT3y7}U(H^R8b~0`#v0sanRSw}rS6&p5!($B^%0 zp!Ryjymmr&A(NIO!OT)#0%IVRhmU~L{j2X~VYEs58$^Nq4uGkD(6MXOgtBk)+98#h7_@+yV+J^X7}zMRZIr&+0Z`^l{cr5FgUF@f9YN(BCt6@ip756UzR-5q4>idp=b!y`uh`)6j!s6*v5SVZQREAzI=2 zwj^vC?|n4YaAPLG=S1b0r7FWi++L%7Ql7mE9k8fWKBUkKI<_W&2pTLR{^to?3IJD< ze?HBZ6w$V2b|G`#d_Xz}kFXl(+Y1T&c{wU9mn~G>^#s8}IqSV-CGux8Tb$>#sg>~& z&f9s9Y3!F9QsTe4W6X$eUbh6wCGZt6{R9zAx~8R{;V4?7S)dbKdumXSLq2tD9OiRr zumoUmEVy}K(Z|oOu7+SWkQ#0Jx535Gy>YQ0G?;RBTqgA1mG(?=AWAj1@j{}E_>BQC(*)x{Vipg1M-qn^+Ma^1R#-)diFkd|X z93oc0^vS3x(2P8se&fTGr&L~)(Jp(o76$E{XZ3$SsHdZGEgnkg0RizhGf^1dWX&sr zJU85Uzt?ZX-C$`uWNG`Gh=PM2#5tB*)^?TmS&E!wP6fAuG>3?*#o? z7h#_lv!_|_^vx;?R)2cbbSjT*qm6HlxU_8%<%0C>8R|9oUPzhsd?tHN!n>T-%a}vb zp*hgOVYc*S&G2cTv5Z0O^a;+pN#58#KJcLy+9<;H{kQyPc8O?NT2o5qewf?jIP~^j za9dcy#u>u~C*=JafRB*jL;cPVTQ#P*WA2dHFfi*B>2`8kg2%9u9e>X_l)6|pxN7CR zixXtHWn>DZX|nVNM=NU!3{EnLriw|U0hizy@YBCUIR?@-BY4w_Od#!VzDz~J%B|$t z?z*^FAm>K!pkNRUJvKWyX(fKEUp}*tz~|dvB8F0ptv>g`;r`ZMQ)%aYLi2jbhgh2P z_uxQOH;_q`9q$!TVBeyh0dAg{#LXxA;V{2uc9Z+89-{suWyWE>%18TdA#6XW7xiD8 zAg-$jUij5%O!=4dZ46}YyyV1%4m3h6Kc?v>k`cWZ9zL`c`TUEbr9)4ci=K&enuT!k z1AfiT$^@gaatx0xjCCl-k>2|;9nBSwBh90Vx^Hkrt*fAr4aS_DC{@kbJ6NevI4Jb; z=}ptEdL=<27iCH%F1s44x6%_D&C(IXFuVOpeIMIjD#vzp#p-8(a}WQkpo-KPQm9CX z2}_|;*)QgjjSaN02@_*Z2;EMYPxCO}|FiPQE05z%8VDB}RzCHxLXIFWD-|9WyZB7Y zi&@Oy{75h*UT>g+gf|^Ce{iP|9tKL4?p!=EZ};kfHy;@xFEl3qDk*WQ^wGA+Jj3V` z#pyhWU_jLkcB#c~>64C!--#ANRj(5hChYie6P9c=J4rlC-?rcAz(-O4a<-yh0l+&* zwL)fWmEU+(^E9q_-4Q@+<}X)GQGYtg(~Fr(LoiHUV~hQA%=NLL7%s~$f!cq7V!Y-k zgrpsFXx6sa5<`0)-ic-xJl!zxT6C^zvm$aebJU%2u`9gc=&mS2nq+496@+ABZM>m) zYNB`xn-Tx>WF~S9!i!oX-af36fhSF5SrxM}s;v||(O1@=@Hr__@f9&eaY5@z7*ihv z=kA(Vs85?S{TMCq4Qo4)!`14oP;op*L|(EYU^O;`Bi$B?{*RTL_yIJy8zH}BDrF~r zr51QQ6G#6wF3m?aeyr`QT4{`yyUrqiEfu!%NO%4UGu_B!`KSLUGKk|&`b12=xS za~NSnkH7;n+qUK?4Uz}-hCld1KJ1!)EY$;{7ukg4^5io##Cl3-J@mF*~jP$%qk>_2#9pIZ|T(#>K{pUG#tk%}^$r z;SInwSt=tAdj0XA2YD#Drc)jt|E~}Ia`;Vq@vyBXHS)W!VxeQ-MOVHa2)bHeX}L0t zbA|$ar=rJ(GnBTW7DPsR>67BegNS%Tkqs1d(>ZX2b9pHSm2BT6%=`5>Xa<0aREBZN zE}+{$(jN5%QZrl$1avae{qFTeR#PMImNv0-Sy08;v@Ti5|F6kA>Oi!@GH@2RFjVfL zcW`p&B7=*`x>K+ihud5!ao@R6B>G%x(}mDH)!>2qp$3*FetMz-SeG)hOmQGjEqKn% z^e^1z0w1z9-Uug_>aj@X-|#KfU~VFFLs|sWg83`)Of6e&7WEVt$MKfhvE!?9jAT1^ zGGrJu*0Ae7_Y8k;&s4h#g_Xu)e+n_Jjb6bR3AHCfsE9}Kv4$l3RTRYRNEgZB`(N{x!a{+kLi8TsG7Vdr=Vq&GRCM+DWHBna1(RXdy z34}%115X0}zhe3)bFXgVUqklSCFNjGW@@7DRhZ$&t$*akJa}c!dC30OE_5yBx~XQb zFY{X8N|^h@fvmNjO`NuDB#e9<=#u>TfO}OZA1;K}4wHHV@Zh?j{}m7g;J=Dv&o>se z>-+h;+1~rPR@Eq~lB57&BgVmGzxGvYM4)A;GcH6vzR?);;~Uk|T-y8)2Edss*3CY2 zCVVc5(lMxq>11)<^R8|SlgaxM69}iR!zZdukI@TSWP%pI_LVa-pmq7*Q-+_m3x zj$<2iD;LxAl(v`pDZ#wo+osJ)6nzDU^wLwoAtHbAu)-r4+K zIB2ZE%htjYt=dL_Al*nC>a0ENQF4k5oMEctaXuiRd!KoZ1=_U$BqFR|1I{iflbI8w z6=$=?lw|XN1=s2##N|JHZ7DQU4XyRz10aP}ty#P}Xlm?JD@?NvNrNx3+wWZ$b8~bW zqLne~Sr>QIs_g>pmxC#kQy;1sj};q!!%2h_#2YS~{E;uRTL(CQDfu}7F6C}DE`H+f zL@RX@0w>3WW;wlvD4JjE8DB{VX)&%<3F_+OhjD^m?lmX||M;pGOp3ko9$u*XLCBDr zoijlh{dc<7NA+{3hDl`K=Tk|LXeJ8cSHAXliRa-Rz{)Wfl2E19Rbl2vVhLrbu7sC3 zUJz;A{9aP}S=X+Zdz@|Ba;eWghjieUbv&S$J1V}M-li0ttEYpU>{$b@`JGtX(x)Y+Bxt1 zcXQ;*>BhTTd(Oe9Utn?(t`(KN5=Q~3|D?x&V?S9L9$ySZQ7@v9xR~Z@-I)CMja<$m zv>WF#`XTH~w9}hwnxbw(MFFT`Or(B%AJj^R7HyRcQx1WrFe&FD)Z%JLeuM7{;amo7Z6aVMov8FB|(7JPRv$O-~v36*%YJ#f6A^eIr0H54$~ zVhH_4J8TgAVkn>Mw?P`+O46>?ga7)SbpsnvOBC9eTurk&T@=;5RT6P{+Gqq$6BZ)IEvFu*xYw!_X=(h5(SLrqtYL)X{9$B$*}@WxWytQ+k!LSs#R%IQB!MLy zwrBQDGD|Npap-$B4?G9WFSH~`%p`FSu-k!tSvP;bb&@}G`9w~sg>zNP6Cq|2(ql+f zZ~_q*s3LPxD=i)PD^d(1DEzo=Os7tf93*y0X5-FoU%xUAI?zenSUZ;H zknMXHY;~HLHwc6(^;1uJ#hSRcFx7&ZuOfB_sjr2|^Foja4^?xETy#=rtnng)zqFRA zCanP`mpQREKhUqkMR6ahX&5}HF)?a1#Ai}hJ~FO>0efYd<#di+NT#A10s^OQoX3Er z-BOV)fFhIVw0WX$0^|9OSIxnk%2v=-VOP3HDGd+leSO0`EwuV*W+zZKAoz~nh4K3t zY{yBZ-rONAQ=x7iS1`G)fRIRIs-YhCA6$(DLNg3|_9dY&EJ}@uLJq8wg1GpVG~;BG zm_L3X|K0Z#pIK9II(RXYamIGq^VuPvl*4dIn#MP7Aj*%b#jU6}T!q{V4LS>$8DI9r zt3gkA(->^eU#ZeFfA_Z%@DJgO(g=H+z5Pj9z*=uc%Bf_dGY4r4(_Ki)?k6 z>s6gMViOSX$k{Z7pHQkP@^N#36--s9?C1xrJmZXiKp=B#^Ke5m&8&sChEn$LXQ@}skjFA}OpCzX6XGN|5t#p$3qj5a-?SwU!7<(ZG|u4B1P_XT z($jM?bXOmW?pIKLQ*QeO3M}1F!QUrH`Hp_D9L+*%u=R@l>j!wA0zs#?6gd!ojt#ms zN%GU#+>xo^8DVS_0*k{^J{_hwM6BV8Z@7tGXm7JpEy zgMo!Rbn_o}e}=6qTGak$e(%h!v1XN_b>^p#v82IexbjT%tbWpWyMH>XUckI74NE{@C$>R?_rGJSKC>qi~8Lcb;&Itn#o15Cfh`;wR4U->Smx)&h zbb(4!Z_t&4LHxym)Od-(CvVJtQN4exXTwr9Pdb*e({HaqIz&Yy<61sXDVfNV&kP4+ z#g2oAAR3Rwcjiw|22fK+9#!1yDxU6+k|{A3l7|x*NUO7weq$7G$WKU>-%Q77?_IIQ zvtEg94hGb8D`M0YjZR5XI=8{-Ht-(ZwprE&P?_in{Cy1qy$t|j>=XxTS8~7w6Y^#S zH!ZvS3Zg}>_(#r=6@Jh`Q6~_lZ&XTM?f;*%TKC_7ad@CBN*`KtYEEc9pZQR;bRMyGW>oD^FD^Q za;~FP&u&r$teq+N|7R2@+I2`GB>!JubNl}b(r-Ei_d)QD1+AV$;U${)7OvCk zH?3mGqtoZmenLNVivhkoRqC}oQknNqeNB)>z^h`$9wRQ6xnt|0isLCmtOFUY)i!HT2 z&{BL)Ac_b4w759vU#nQ`8n07V8B;7Q(nO3-H9;C+waP<1j27xOgqHjQP{rl~ejB)< z!*jdXBX~l~Glje>^Slpyvqc!JN03Ww+~MCijJZ1cS6i2_%=j6N7EXa~ktJ|pXBfDk zLeC!$0X1y-<2|f4MZ|OxMYDEA_tCg5RgjxpEY4`@E!ju1ZDzaw?{8`{kfnSZ-eU{Z zh77d!w4Il*N<|(P!0s5C3h4a4U$RieIZBL@4ZmFl`MSSJM8>yaE$rc~1{a|y1ExMj zWU>!q|CV5}>)51m@b4d)R@oL7ZDr6J8Eus=PK*HJSAE+zBK*P=Km9K16o?~@r&L>M zie8MD&UI{%CEd6w>6Qc>q6CJ3;Zts5Y>-nk-=6*(Q6P?39oS}9v%xab_$S1* zgOH_Xy!%IPO}I^D@$2$1ot5Lvbx8I_N*I*SJ<1evMWuzF1@Eo{^ZOkPLIwxZbyZeC z?XC#WDeXhAP2hVO2o)@><;Y!Wm@Dx$P_nKRjb?NWd1=`_Ut^YKriN)m76S@i%s|^= zmO0TX1#?e)gp?&T44P^3_!z$`&g^!2*;Ov1c*V?`AQyjTlluoVgn5qaMK zD`icS8De5cn8Qgk<;|ovEwz(4f9-YK(11nnJ345~sw8#8&_(Ry+HNvxWLHNEToxiZ zl!Dr+E;4BxiaI~61=gwH-Ipf%wEIxG{h%P!6fuWw&d?(mq*TtYg;;n~&HOfEwgqI) z6HF`AKC$L%;HuM5(QrTbRt7#W%>ASERC(9EA^nNo$e_3kNvP@ixkY_jaSo)F|5QfX z5k)6&hVEaaY>5X7+8XL(XrG!pCFaS8mZFbW z=v!877ChFsmV7kV_sg1?)n=K01% zGicW>;v_rnjc?+hv93Tu;*HIKpKxrEJD;?d<)3EcKwr-poAjn#Dek(r%aSht-$$R6 zL6oN9d9&t-e^*IDf&RE}&3KBorhbM6|qboHE9@wX-&CX_l#Q8*{x-eZ#6JihFu{m5kTq zGMo%aX>Xd!tUQ*@O!9M##BVa znYnr$2zWxv)DXr_YrWajjjBp&$oJlgBC1-Or+I{{Yak8e?=MrX@-hmuHFtWQBRfJX zxHj1_1ZGI|Zf9YiBOcVLs~tn#pkb&X-m3~+imJ531s}42Xqs7P2CT+I7>&?xpF?$$ z$W*t}6?MZv`cqXA9{?o>YUvl`Ds=T?2*bp${ynstH8)DXtu}WQ{=z8SYIe+^h$@2% z)`HEh7lunRv?(e%O?kdLjGN9{>tH$Drokl!d7NK@6Sl|OjGAhx1kaZ6MHv#JKc^gm z0B>0DC3h)CyFx9Q(LuZJ8%(zikmmZ?6vU^~fs;i<-|9Z6H4EtJo1Ca$ERkxc_YCoa zG-ko!^oT0j_;rBQ;lOa8pVcXrvbBxNa~8IXL^S6)V8A7+){e@4`69F2ae@yO>%qqkKt zTtVCPKxlh1Aiz1CHT&jxr$L}Gg{||?kS2FoxR=@~uOoulo$~&E`ZeHokeJ-FoCLddBnQ5f zNkX?Jj|sN*uTT~G&qwTedr4T)OArqjmlYRcg)e2YGnWZC0nSkDtC_Q6;}&IR#a z{C-ZR`DHfg5msA%!H9%<$X!s$la|iLls(BO@M!O6Y6`}klsdc|Z{9k1z)-PS>vo~Z zQI_y}-uliG^2EP=Q!1Tc?}c^YB&(axQE)4wjpT@h+G3SmA=NH26Y7e-E z8XCQnc&Oo-s|(jipS6?|97~+})?Frp&z_AYaT`*+4YevhQF1>-bnuOTew$-!xiazt z&nkaq;}GXjBt1TxYKb3iP`E9N_#1hFe-!WBNG*xp7djM5C`FoXm0mM z?kdsO!0lCp1lvMyq&YnJ4W%f)`*kl+?2l^$I-9@|MZKpkh_yt69rxFa%8%OJo~Dog zZTi0mljyZ?nrz8Mt_zt{xnK|(JXs-Fdw3YRfhfzc>PKpaq`z`75{GYQXGQ>EYO&{nN9FIT;c)xG}n3S*-9}zhRSXojiQU zl%>;C4vlsimO702iKB}@EhO@yR7Sox8+*R_ zq~Iu^+a{s%cG?Wi#eNm9DQ*w69Y=8ZM*N7*tIj;w8BN`~f?VctXaD#?Di^a~?P0>C zPzz>9`%E#g7SSwM$z&eW1P9S6n+-gs>(LWIhU15E4kx94PVh$- z($kDQe(IzUYau0g%Tiv)-QgCBkG#^!(d|5&GNXQgvNf`cxG(r8rH{Atc|ZT5#HCDq z1IO;*=bm^F{^`(cN*p1n(w-s}38%iY`wwOCjJ9(u40FGno{%cqe$nNDqcrFa+*>>A zP*vHt&7maeM?hl4_tW-Y>m9+|x6vBz*&e518E>0`kvh@t^hE4?D4N`Ui-wKM>O}Kb ze)MY^?+%H#r{fb!B!ux|=w?>l@nm#u+T9{Rm@WabNr zXJJtY3Rm@YUwsf|Dzwbik|?d4+tj-wv{r4ozL$o$7GDiO6c8uvL>@8AL4s;sT}0N? zllFoN!sw}CtP_c-IJ!FM9v>iP+mjR!H*~}-axpIG&v$u!i>TLV04b>0!x9d%Z^IUzUOf&y~ zCkXB0+Ph#l`4Ixyb!g6NShEFFB;#Xt#rRWuz%__y0v1`Vf zhX5{TrYcv<1`BwP~+GIpgH7CM0O-+!NA#**x{E>4drvpAo{K+fSO_k$I0{K;K@$|e^Z)m^Cm{I zR0>P-NmRgkM1GP4+t?jj=K0|UD=BtSw;#RzCl;B=VX!W9D@o%BeE~;8R}>?6P5k zn_U!!{bCt<-Dk0?dd*e{<2=jYjY+zUCOA*$zT}A=%1s#yVRtX82U4AdmKMRn^Ut`h zT=qzI-Mbvu=a2RpQrx5Vwj0P?-ZPM>ag;NA@@V<`(poiq>V?>N@d z2bklWh{eV06N~HnBmtvj0agmMH0;zV9;RfW3xJrsT`+m2{$}ji@OG?5(9BKl;n?)r}yM-$0-GQh3pnP@PwA2WwQFpOv&@;v6kIyGAM>?BajaNi$=1rSix%iSiP*6PsjE7kRoJr6Ka7ZY|sBQeU2SgBdL1b(bgZ73J*o2 z3A&-WOMMldTrwRL(DQ8Nffj7#5Lr<|m|78J!-4p2{F=||4oMCpXfT$9#1;?>9&vnk z=JQe&M4#yuNM$LMvUxAIM-jtN-IUCo#EoToZ>lD~6dK{^HE`}WDG3o$3l-9+H8LLz z5+zS$UMBhe0$Ky^mx(p4ZZ@_@6ZI~7MdJ1`)=Ko@JD?U;FiyK}?q{I%8tB)|^?w_2 z@7{{&v<`A~ro0!%17W``+UKt^%}ZRm5w$m+!2s0I!f3-r@IKD7im{9FcCJ=+rtlUo zX7wIBdCLMsC@);H;^!`$WEmKNp`c>tmT?;)u9t{H3}DFAk4$hEyVQZ`?Y_*lqL#mT zG*-Gu7ZT3+PO-R9l;kzU15AAYB9sVP`Zbk6=l)suDx_nxF3Pt3532pV_B$17Av>d( z!O~~GAz|t=UjQB1`ssUorD7luhol1x4NqT+?sHEdYI7H9nkH@Cjj;!(=}zE;bh{;c z352H-_K1R4wLL#{8gp_=rF((-G|tHrcDayp4Q85odpYSGvKpp3P32om!Y9Z1FE^O$ z`iE1q!~}GPBQq}aYGbvpeWpVSmLJJ2H;kf7c#>&s=mG=}?#IP2fxggCVbL5;(!9A- z(#v>cSF)`cW+~?Va5>9`5+ORd%?_;0qU!ZGMC9_)k*M>5m3U3Sqq7WV)Fi&69)tHe zfT?Cx_|M(zo)S)OKlKDzs296ex}r@U#l^I!$XBN(zP0JqsW*?mzJAq%_qLnk5A9|6 z(-H7F#BX=fRk3~Itie)rZqJ^= zX{Mbx&1O5x5)F`Y5&o4#sTQ@6h)jU!;yDNWQysJ48@W$%v&4CMzm5C`i~jw!Q?KUT zWv-2WptOS;ZMH98uR^G*Y(SI8)zlw&G!svZZt3$V(|@qRuXJrM?1h@bQJMC!QNoNXseE7Q#kqK9PxC3TUZUX^MtnRzEZk^c1vg4^Ng~w0ETy>Je z4x)zZ-sU)EgfOSa<#rOHj(U;k+x%8H_J7Y9n`G6~I}roGZb5|1mwbE8@wfDXP8n@$ z;|INi4tMP06ZSg=AFCFvWP;2EG`xaY^6=`9}Y&mhoaPo|!H$ZvtWG%B%8iMq=vtCyLOA+=B*@!;sa; zEai;mV1a#xH|Gld>6tNs@@{VhIC6V8p#N1#aJZcw6~6Bac+&=M{rH$G(TcV%EA# z4t(@dGTIRnYyc9%VT48IKYb_73p9j{KYB{q+SNJOti7?;us2%;5b^YG&2nd`JRoms zv!gylTZ9iq8Hf6M#`JFm;DDE7grfJ6Lh^Uh6cT3(@Y9DDZF*Fg*-V@1cCFNiWx8B1 z^o0`|PZOSQm7=}n`hG?*(M{l=12!7=D$=1{c-0j`2k)dw+pR|&v!IDpf|+$B6{2pp zvDZe>L}P1_Wq|JHkrB|=qmrE(50UQZMKfBwZmG|D_-v%~{NuTdbXN%wB%?-Dz~5{| znkjkJOJ-UN%!84^ZB5QJ1bRc2mN;N&4vBs2X}9g0N@f(Vxd4>>14Uaa@oiOmZzjuTYEC&r2Fw1UG(>A!KC ze!SgSdBgnCP5&wEUWHV?%tJn@4cQ$q(9}co_aeS7(ZA~sGkPegWcFCw_fuRR2n>f% z%SU$9L>H=BL7_7PY1`X)U@horNAon1)sFZpWZCgGjMb-)gh|PjXdT3o=-8k@id`|9 zT0#IsigB|XZ{$vb#HklV12%J20!t~;s8}jdcDJ_ZQ_^AJ=SpQL;7IUVqO&vQMEA{D z?+Hf^p}fYA7yyUo*6=%m%k>2s9SGXl@4}u@3&k;`z3Ey|-q0uGC2>>De~Sea$?uzK zg(nO8Z!rDP#Y&gVv+2bqSb5L&!c5A(q+dl^vFCr@DTl<0Xt!9JuUxJ*9Lp}P&z^n` zG@AZkR|FOVE^_Ppjg_O2_izv>d;tBY@qYdIFIoAnI=_3CMRC}|v4TLS*Gaw{aedStyb-@9-tK;eu%SErEbEEv8X1!{x4~mN#0Y(bAh3I2! zT&!$|7$W|36BQ|AWfv^-PllGA#8ewys6M_#6BeHrl|nUfj6`>RwPHfJPxk)#Gxq{8 z=_^}R&ff6EPv|n$W?F*Bgv(0k{ksgrItrQBzF;yQF93Rj7Z2=KEg7sA0fu33cWM=%;y{xg8uyPc zLo6>*C7M9Li7n~hl2QNw004nA2d)p-?a-Q~Y)Iv6;x6@3Fh;Ht>w!&G*8f$uy@537 zQNj9#M=noo&P=lXjzI%k?Y$`#cc{p(y&6zCB8lX@@wLMb8`bo|b2CX2Y1xY``6AUO z8a^#-0Qsy81b)Ebvq3(Dk-S3#x6; z06tKPdpDGqJ9n9JX~8naT{;ya%Qv5ku38P-XlE{phTtDY-3&03o$0N0Em1-aF?Ho zi{*H?7`fE_iLPwfC_FX^LN0JC%=B6*K959gp5$@C`v~EvSbR0#P1M>4p{gB8|Jjs% z9k=p6-Ot>rqoTJ*F;PvtqMnT?&FlyDzdEbk^3bo3EZLr5f)M-JcTzziuCWOK000*T lz$dN&34x9P2MYlJ0V4we0R>$E01yBSgQf}r;}$BW004(o!q@-+ literal 0 HcmV?d00001 diff --git a/content/zh-cn/posts/csci-1100/hw-1/index.md b/content/zh-cn/posts/csci-1100/hw-1/index.md index ba399bf..60d0d07 100644 --- a/content/zh-cn/posts/csci-1100/hw-1/index.md +++ b/content/zh-cn/posts/csci-1100/hw-1/index.md @@ -120,8 +120,6 @@ Good morning ! {{< link href="HW1.zip" content="HW1.zip" title="下载 HW1.zip" download="HW1.zip" card=true >}} -*** - ## 参考答案 ### hw1_part1.py diff --git a/content/zh-cn/posts/csci-1100/hw-2/index.md b/content/zh-cn/posts/csci-1100/hw-2/index.md index 449e48c..c7f3819 100644 --- a/content/zh-cn/posts/csci-1100/hw-2/index.md +++ b/content/zh-cn/posts/csci-1100/hw-2/index.md @@ -182,8 +182,6 @@ repost: {{< link href="HW2.zip" content="HW2.zip" title="下载 HW2.zip" download="HW2.zip" card=true >}} -*** - ## 参考答案 ### hw2_part1.py diff --git a/content/zh-cn/posts/csci-1200/hw-2/index.md b/content/zh-cn/posts/csci-1200/hw-2/index.md index 2554097..1f1766a 100644 --- a/content/zh-cn/posts/csci-1200/hw-2/index.md +++ b/content/zh-cn/posts/csci-1200/hw-2/index.md @@ -10,7 +10,7 @@ author: link: https://www.jamesflare.com email: avatar: /site-logo.avif -description: +description: 这篇博客文章详细介绍了如何在C++中实现一个简单的拼车应用程序,作为CSCI-1200课程作业的一部分。该实现涉及使用向量存储数据来处理乘客请求和司机取消操作,并遵循特定的输入和输出文件格式。 keywords: ["C++", "编程", "作业", "String", "Vector", "Class"] license: comment: true @@ -29,7 +29,7 @@ hiddenFromHomePage: false hiddenFromSearch: false hiddenFromRss: false hiddenFromRelated: false -summary: +summary: 这篇博客文章详细介绍了如何在C++中实现一个简单的拼车应用程序,作为CSCI-1200课程作业的一部分。该实现涉及使用向量存储数据来处理乘客请求和司机取消操作,并遵循特定的输入和输出文件格式。 resources: - name: featured-image src: featured-image.jpg @@ -396,6 +396,10 @@ A: 与 Uber 相同。保留一位小数。直接截断即可。例如,如果 - 成员变量是公开的。 (-2) ```` +## 支持文件 + +{{< link href="ride_sharing.7z" content="ride_sharing.7z" title="Download ride_sharing.7z" download="ride_sharing.7z" card=true >}} + ## 程序设计 由于这次作业比较复杂,我们在开始前最好好好构思一下怎么实现。这里我借用两种情况,也就是指令是“request”和“cancel”两种情况分别设计它们单独的流程,然后在主程序中使用这两部分。姑且把它们称作`handleRequest()`以及`handleCancel()`。 @@ -461,3 +465,829 @@ flowchart TD ``` 有了流程图我们就可以慢慢实现它们了。当然,不一定要真写`handleRequest()`和`handleCancel()`两个function。把它们的逻辑直接在`main()`中实现也是可以的,我这里只是为了思路清晰而已。 + +此外,我们要设计两个Class,因为这是作业要求,也是为了方便我们实现功能。 + +```mermaid +classDiagram + class Rider { + %% 数据成员 + - firstName : + - lastName : string + - gender : string + - age : int + - phoneNumber : string + - rating : double + - pickupLocationName : string + - pickupLatitude : double + - pickupLongitude : double + - dropoffLocationName : string + - dropoffLatitude : double + - dropoffLongitude : double + - vehiclePref : string + - currentState : string + - driverFirstName : string + - driverLastName : string + - driverPhoneNumber : string + + %% 构造函数 + + Rider() + + %% 方法 + + getFirstName() + + getLastName() + + getGender() + + getAge() + + getPhoneNumber() + + getRating() + + getPickupLocationName() + + getPickupLatitude() + + getPickupLongitude() + + getDropoffLocationName() + + getDropoffLatitude() + + getDropoffLongitude() + + getVehiclePref() + + getCurrentState() + + getDriverFirstName() + + getDriverLastName() + + getDriverPhoneNumber() + + setCurrentState() + + setDriverInfo() + + toFileString() + } + + class Driver { + %% 数据成员 + - firstName : string + - lastName : string + - gender : string + - age : int + - phoneNumber : string + - rating : double + - latitude : double + - longitude : double + - vehicleType : string + - currentState : string + - riderFirstName : string + - riderLastName : string + - riderPhoneNumber : string + + %% 构造函数 + + Driver() + + %% 方法 + + getFirstName() + + getLastName() + + getGender() + + getAge() + + getPhoneNumber() + + getRating() + + getLatitude() + + getLongitude() + + getVehicleType() + + getCurrentState() + + getRiderFirstName() + + getRiderLastName() + + getRiderPhoneNumber() + + setCurrentState() + + setRiderInfo() + + toFileString() + } +``` + +## 踩坑内容 + +1. 在打印`output0.txt`时,looking for 后面要跟一个 Rider 期望的vehicle。但是这个vehicle可能有元音字母,所以要判断一下,到底是用a还是an。这是一个小问题,实现起来并不复杂,但是别忘了。我用了一个function来返回a还是an。 + + ```cpp + std::string autoAAn(const std::string &word) { + if (word.empty()) return ""; + if (word[0] == 'A' || word[0] == 'E' || word[0] == 'I' || word[0] == 'O' || word[0] == 'U') { + return "an"; + } + return "a"; + } + ``` + + 然后在后面配合``的`ostringstream`的方式拼接从Rider Class获取的字段。下面的代码就展示以下逻辑和结构,不必较真。 + + ```cpp + #include + //... + Rider &r = riders[rIdx]; //just consider `r` as your rider class + std::ostringstream msg; + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + ``` + +2. 在处理司机状态的时候要特别小心,一旦有变化要马上更新,因为一些逻辑是依赖于司机状态的。比如当司机从`On_the_way_to_pickup`变为`Available`时,需要清空Rider关联信息,并且再自动为Rider找新司机。重新寻找司机的时候,也要避免重新找到之前已经分配过的司机。 +3. Class的变量不能是Public(作业要求)的,调用内容必须用方法,而不是直接对变量操作。 +4. 根据作业要求,我们不能用`auto`类型,这导致我不得不修改了for循环的内容,比如: + + ```diff + void exportDrivers(const std::string &filename, const std::vector &drivers) { + //... + std::ofstream ofs(filename); + - for (const auto &d : drivers) { + + for (int i = 0; i < (int)drivers.size(); i++) { + + const Driver &d = drivers[i]; + ofs << d.toFileString() << "\n"; + } + ofs.close(); + } + ``` + +## 参考代码 + +### nyrider.cpp + +```cpp +//An implement of CSCI-1200 HW2 Ride Sharing +//Author: JamesFlare +//Date: 2025/1/20 +//#include +//#include +#include +#include +#include +#include +#include +#include +#include + +#include "Driver.h" +#include "Rider.h" + +void debug_print(const std::string &msg) { + std::cout << "DEBUG: " << msg << std::endl; +} + +bool isPhoneNumberValid(const std::string &phone) +{ + if (phone.size() != 12) return false; + //xxx-xxx-xxxx + for (int i = 0; i < 12; i++) { + if (i == 3 || i == 7) { + if (phone[i] != '-') return false; + } else { + if (!std::isdigit((unsigned char)phone[i])) return false; + } + } + return true; +} + +void loadDrivers(std::ifstream &ifs, std::vector &drivers) { + //read the file line by line, total of 13 + while (!ifs.eof()) { + std::string fName, lName, gender, phone, vehicleType, state; + std::string rF, rL, rP; + int age; + double rating, lat, lon; + ifs >> fName >> lName >> gender >> age >> phone >> rating >> lat >> lon + >> vehicleType >> state >> rF >> rL >> rP; + if (!ifs.fail()) { + //change "null" to empty string + if (rF == "null") rF = ""; + if (rL == "null") rL = ""; + if (rP == "null") rP = ""; + //create driver + Driver d(fName, lName, gender, age, phone, rating, lat, lon, + vehicleType, state, rF, rL, rP); + drivers.push_back(d); + } + } + ifs.close(); +} + +void loadRiders(std::ifstream &ifs, std::vector &riders) { + //read the file line by line, total of 17 + while (!ifs.eof()) { + std::string fName, lName, gender, phone, pickupLoc, dropoffLoc, vPref, state; + std::string dF, dL, dP; + int age; + double rating, pickupLat, pickupLon, dropoffLat, dropoffLon; + ifs >> fName >> lName >> gender >> age >> phone >> rating + >> pickupLoc >> pickupLat >> pickupLon + >> dropoffLoc >> dropoffLat >> dropoffLon + >> vPref >> state + >> dF >> dL >> dP; + if (!ifs.fail()) { + //fill null with empty string + if (dF == "null") dF = ""; + if (dL == "null") dL = ""; + if (dP == "null") dP = ""; + //create rider + Rider r(fName, lName, gender, age, phone, rating, + pickupLoc, pickupLat, pickupLon, + dropoffLoc, dropoffLat, dropoffLon, + vPref, state, dF, dL, dP); + riders.push_back(r); + } + } + ifs.close(); +} + +std::ifstream loadFile(const std::string &filename) { + //read file and return ifstream + std::ifstream ifs(filename); + if (!ifs) { + std::cerr << "Error opening file: " << filename << std::endl; + exit(1); + } + return ifs; +} + +void saveFile(const std::string &filename, const std::string &msg) { + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening file: " << filename << std::endl; + exit(1); + } + ofs << msg; + ofs.close(); +} + +void exportDrivers(const std::string &filename, const std::vector &drivers) { + //save drivers to file + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening output file: " << filename << std::endl; + return; + } + for (int i = 0; i < (int)drivers.size(); i++) { + const Driver &d = drivers[i]; + ofs << d.toFileString() << "\n"; + } + ofs.close(); +} + +void exportRiders(const std::string &filename, const std::vector &riders) { + //save riders to file + std::ofstream ofs(filename); + if (!ofs) { + std::cerr << "Error opening output file: " << filename << std::endl; + return; + } + for (int i = 0; i < (int)riders.size(); i++) { + const Rider &r = riders[i]; + ofs << r.toFileString() << "\n"; + } + ofs.close(); +} + +// calculate the distance between two coordinates using Haversine formula +double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + const double radiusOfEarth = 6371.0; // Earth's radius in kilometers + // convert latitude and longitude from degrees to radians + lat1 *= M_PI / 180.0; + lon1 *= M_PI / 180.0; + lat2 *= M_PI / 180.0; + lon2 *= M_PI / 180.0; + // Haversine formula + double dLat = lat2 - lat1; + double dLon = lon2 - lon1; + double a = sin(dLat / 2.0) * sin(dLat / 2.0) + cos(lat1) * cos(lat2) * sin(dLon / 2.0) * sin(dLon / 2.0); + double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a)); + // distance in kilometers + double distanceKM = radiusOfEarth * c; + // convert it to distance in miles + double distanceMiles = distanceKM * 0.621371; + + return distanceMiles; +} + +int findClosestDriver(const std::vector &drivers, + const Rider &rider) { + double minDistance = 1e9; + int bestIndex = -1; + for (int i = 0; i < (int)drivers.size(); i++) { + const Driver &drv = drivers[i]; + if (drv.getCurrentState() == "Available" && + drv.getVehicleType() == rider.getVehiclePref()) { + double dist = calculateDistance(drv.getLatitude(), drv.getLongitude(), + rider.getPickupLatitude(), rider.getPickupLongitude()); + if (dist < minDistance) { + minDistance = dist; + bestIndex = i; + } + } + } + return bestIndex; +} + +int findRiderIndexByPhone(const std::vector &riders, const std::string &phone) { + for (int i = 0; i < (int)riders.size(); i++) { + if (riders[i].getPhoneNumber() == phone) { + return i; + } + } + return -1; +} + +int findDriverIndexByPhone(const std::vector &drivers, const std::string &phone) { + for (int i = 0; i < (int)drivers.size(); i++) { + if (drivers[i].getPhoneNumber() == phone) { + return i; + } + } + return -1; +} + +std::string autoAAn(const std::string &word) { + if (word.empty()) return ""; + if (word[0] == 'A' || word[0] == 'E' || word[0] == 'I' || word[0] == 'O' || word[0] == 'U') { + return "an"; + } + return "a"; +} + +int main(int argc, char *argv[]) { + //take 3 arguments + if (argc < 8) { + std::cout << "Usage: nyride drivers.txt riders.txt output0.txt output1.txt output2.txt phoneNumber [request|cancel]\n" << std::endl; + return 1; + } + //load arguments + const std::string drivers_fName = argv[1]; + const std::string riders_fName = argv[2]; + std::string msg_fName = argv[3]; + std::string updated_drivers_fName = argv[4]; + std::string updated_riders_fName = argv[5]; + std::string phone_number = argv[6]; + std::string command = argv[7]; + //turn on debug mode is last argument is debug + bool debug_mode = false; + if (std::string(argv[argc - 1]) == "debug") { + debug_mode = true; + } + + if (debug_mode) { + debug_print("drivers_fName = " + drivers_fName); + debug_print("riders_fName = " + riders_fName); + debug_print("msg_fName = " + msg_fName); + debug_print("updated_drivers_fName = " + updated_drivers_fName); + debug_print("updated_riders_fName = " + updated_riders_fName); + debug_print("phone_number = " + phone_number); + debug_print("command = " + command); + } + //load drivers + std::vector drivers; + std::ifstream drivers_file = loadFile(drivers_fName); + loadDrivers(drivers_file, drivers); + //load riders + std::vector riders; + std::ifstream riders_file = loadFile(riders_fName); + loadRiders(riders_file, riders); + if (debug_mode) { + debug_print("drivers.size() = " + std::to_string(drivers.size())); + debug_print("riders.size() = " + std::to_string(riders.size())); + } + //check if phone number is valid + std::ostringstream msg; + if (!isPhoneNumberValid(phone_number)) { + std::cout << "Error: Invalid phone number" << std::endl; + msg << "Phone number is invalid.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //check if command is valid + if (command != "request" && command != "cancel") { + std::cout << "Error: Invalid command" << std::endl; + return 1; + } else if (command == "request") { + //for request cases + int rIdx = findRiderIndexByPhone(riders, phone_number); + if (rIdx == -1) { + //if rider does not exist + msg << "Account does not exist.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + Rider &r = riders[rIdx]; + //check rider + if (r.getCurrentState() == "Driver_on_the_way") { + msg << "You have already requested a ride and your driver is on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + if (r.getCurrentState() == "During_the_trip") { + msg << "You can not request a ride at this moment as you are already on a trip.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + if (r.getCurrentState() == "Ready_to_request") { + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + //find closest driver + int dIdx = findClosestDriver(drivers, r); + if (dIdx == -1) { + //no driver + msg << "Sorry we can not find a driver for you at this moment.\n"; + } else { + Driver &d = drivers[dIdx]; + double dist = calculateDistance(d.getLatitude(), d.getLongitude(), + r.getPickupLatitude(), r.getPickupLongitude()); + dist = (int)(dist * 10) / 10.0; //cut to 1 decimal + msg << "We have found the closest driver " << d.getFirstName() << "(" + << std::fixed << std::setprecision(1) << d.getRating() << ") for you.\n" + << d.getFirstName() << " is now " + << std::fixed << std::setprecision(1) << dist + << " miles away from you.\n"; + //update status + d.setCurrentState("On_the_way_to_pickup"); + d.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber()); + r.setCurrentState("Driver_on_the_way"); + r.setDriverInfo(d.getFirstName(), d.getLastName(), d.getPhoneNumber()); + } + } + } else if (command == "cancel") { + //for cancel cases + //find phone_number in riders + int rIdx = findRiderIndexByPhone(riders, phone_number); + if (rIdx == -1) { + //in case of driver's cancel + int dIdx = findDriverIndexByPhone(drivers, phone_number); + if (dIdx == -1) { + //in case of not both rider and driver + msg << "Account does not exist.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + Driver &driver = drivers[dIdx]; + if (driver.getCurrentState() != "On_the_way_to_pickup") { + msg << "You can only cancel a ride request if you are currently on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //get rider's phone number + std::string rPh = driver.getRiderPhoneNumber(); + //clean driver's rider info + driver.setCurrentState("Available"); + driver.setRiderInfo("", "", ""); + msg << "Your driver " << driver.getFirstName() + << " has canceled the ride request. We will now find a new driver for you.\n"; + //find rider + int theRiderIdx = findRiderIndexByPhone(riders, rPh); + Rider &r = riders[theRiderIdx]; + //reset rider + r.setCurrentState("Ready_to_request"); + r.setDriverInfo("", "", ""); + //find a new driver + msg << "Ride requested for rider " << r.getFirstName() + << ", looking for " << autoAAn(r.getVehiclePref()) << " " + << r.getVehiclePref() << " vehicle.\n" + << "Pick Up Location: " << r.getPickupLocationName() + << ", Drop Off Location: " << r.getDropoffLocationName() << ".\n"; + int newDIdx = findClosestDriver(drivers, r); + if (newDIdx == -1) { + msg << "Sorry we can not find a driver for you at this moment.\n"; + } else { + Driver &newDriver = drivers[newDIdx]; + double dist = calculateDistance(newDriver.getLatitude(), newDriver.getLongitude(), + r.getPickupLatitude(), r.getPickupLongitude()); + dist = (int)(dist * 10) / 10.0; //cut to 1 decimal + msg << "We have found the closest driver " << newDriver.getFirstName() << "(" + << std::fixed << std::setprecision(1) << newDriver.getRating() << ") for you.\n" + << newDriver.getFirstName() << " is now " + << std::fixed << std::setprecision(1) << dist + << " miles away from you.\n"; + //update driver's status + newDriver.setCurrentState("On_the_way_to_pickup"); + newDriver.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber()); + //update rider's status + r.setCurrentState("Driver_on_the_way"); + r.setDriverInfo(newDriver.getFirstName(), newDriver.getLastName(), newDriver.getPhoneNumber()); + } + } else { + //in case of rider's cancel + Rider &rider = riders[rIdx]; + if (rider.getCurrentState() != "Driver_on_the_way") { + msg << "You can only cancel a ride request if your driver is currently on the way to the pickup location.\n"; + saveFile(msg_fName, msg.str()); + return 1; + } + //find driver's phone_number + std::string dPh = rider.getDriverPhoneNumber(); + msg << "Ride request for rider " << rider.getFirstName() + << " is now canceled by the rider.\n"; + //set driver's status to Available + int dIdx = findDriverIndexByPhone(drivers, dPh); + if (dIdx != -1) { + Driver &drv = drivers[dIdx]; + drv.setCurrentState("Available"); + drv.setRiderInfo("", "", ""); + } + //set rider's status to Ready_to_request + rider.setCurrentState("Ready_to_request"); + rider.setDriverInfo("", "", ""); + } + } + //save msg + saveFile(msg_fName, msg.str()); + //save updated drivers and riders + exportDrivers(updated_drivers_fName, drivers); + exportRiders(updated_riders_fName, riders); + + return 0; +} +``` + +### Rider.h + +```cpp +#ifndef __RIDER_H +#define __RIDER_H + +#include + +class Rider { +private: + std::string firstName; + std::string lastName; + std::string gender; + int age; + std::string phoneNumber; + double rating; + std::string pickupLocationName; + double pickupLatitude; + double pickupLongitude; + std::string dropoffLocationName; + double dropoffLatitude; + double dropoffLongitude; + std::string vehiclePref; + std::string currentState; + //driver's info + std::string driverFirstName; + std::string driverLastName; + std::string driverPhoneNumber; + +public: + //init + Rider(); + Rider(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, const std::string &pickupLocName, double pickupLat, double pickupLon, + const std::string &dropoffLocName, double dropoffLat, double dropoffLon, + const std::string &vehiclePref, const std::string &state, + const std::string &dF, const std::string &dL, const std::string &dP); + + //getters & setters + const std::string& getFirstName() const; + const std::string& getLastName() const; + const std::string& getGender() const; + int getAge() const; + const std::string& getPhoneNumber() const; + double getRating() const; + const std::string& getPickupLocationName() const; + double getPickupLatitude() const; + double getPickupLongitude() const; + const std::string& getDropoffLocationName() const; + double getDropoffLatitude() const; + double getDropoffLongitude() const; + const std::string& getVehiclePref() const; + const std::string& getCurrentState() const; + const std::string& getDriverFirstName() const; + const std::string& getDriverLastName() const; + const std::string& getDriverPhoneNumber() const; + + void setCurrentState(const std::string &state); + void setDriverInfo(const std::string &df, const std::string &dl, const std::string &dp); + //return a string representation of the rider + std::string toFileString() const; +}; + +#endif +``` + +### Rider.cpp + +```cpp +#include "Rider.h" +#include + +Rider::Rider() + : age(0), rating(0.0), pickupLatitude(0.0), pickupLongitude(0.0), + dropoffLatitude(0.0), dropoffLongitude(0.0) {} + +Rider::Rider(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, const std::string &pickupLocName, double pickupLat, double pickupLon, + const std::string &dropoffLocName, double dropoffLat, double dropoffLon, + const std::string &vPref, const std::string &state, + const std::string &dF, const std::string &dL, const std::string &dP) + : firstName(fName), lastName(lName), gender(gen), age(a), + phoneNumber(phone), rating(r), + pickupLocationName(pickupLocName), pickupLatitude(pickupLat), pickupLongitude(pickupLon), + dropoffLocationName(dropoffLocName), dropoffLatitude(dropoffLat), dropoffLongitude(dropoffLon), + vehiclePref(vPref), currentState(state), + driverFirstName(dF), driverLastName(dL), driverPhoneNumber(dP) {} + +const std::string& Rider::getFirstName() const { return firstName; } +const std::string& Rider::getLastName() const { return lastName; } +const std::string& Rider::getGender() const { return gender; } +int Rider::getAge() const { return age; } +const std::string& Rider::getPhoneNumber() const { return phoneNumber; } +double Rider::getRating() const { return rating; } +const std::string& Rider::getPickupLocationName() const { return pickupLocationName; } +double Rider::getPickupLatitude() const { return pickupLatitude; } +double Rider::getPickupLongitude() const { return pickupLongitude; } +const std::string& Rider::getDropoffLocationName() const { return dropoffLocationName; } +double Rider::getDropoffLatitude() const { return dropoffLatitude; } +double Rider::getDropoffLongitude() const { return dropoffLongitude; } +const std::string& Rider::getVehiclePref() const { return vehiclePref; } +const std::string& Rider::getCurrentState() const { return currentState; } +const std::string& Rider::getDriverFirstName() const { return driverFirstName; } +const std::string& Rider::getDriverLastName() const { return driverLastName; } +const std::string& Rider::getDriverPhoneNumber() const { return driverPhoneNumber; } + +void Rider::setCurrentState(const std::string &state) { + currentState = state; +} + +void Rider::setDriverInfo(const std::string &df, const std::string &dl, const std::string &dp) { + driverFirstName = df; + driverLastName = dl; + driverPhoneNumber = dp; +} + +std::string Rider::toFileString() const { + //Isabella + //Richard + //Female + //39 + //301-144-6533 + //3.2 + //Top_of_the_Rock + //40.7593 -73.979 + //Gowanus + //40.6733 + //-73.99 + //Economy + //Ready_to_request + //null + //null + //null + std::ostringstream oss; + oss << firstName << " " + << lastName << " " + << gender << " " + << age << " " + << phoneNumber << " " + << rating << " " + << pickupLocationName << " " + << pickupLatitude << " " + << pickupLongitude << " " + << dropoffLocationName << " " + << dropoffLatitude << " " + << dropoffLongitude << " " + << vehiclePref << " " + << currentState << " " + << (driverFirstName.empty() ? "null" : driverFirstName) << " " + << (driverLastName.empty() ? "null" : driverLastName) << " " + << (driverPhoneNumber.empty() ? "null" : driverPhoneNumber); + + return oss.str(); +} +``` + +### Driver.h + +```cpp +#ifndef __DRIVER_H +#define __DRIVER_H + +#include + +class Driver { +private: + std::string firstName; + std::string lastName; + std::string gender; + int age; + std::string phoneNumber; + double rating; + double latitude; + double longitude; + std::string vehicleType; + std::string currentState; + //rider's info + std::string riderFirstName; + std::string riderLastName; + std::string riderPhoneNumber; + +public: + //init + Driver(); + Driver(const std::string &firstName, const std::string &lastName, + const std::string &gender, int age, const std::string &phoneNumber, + double rating, double latitude, double longitude, + const std::string &vehicleType, const std::string ¤tState, + const std::string &riderFirstName, const std::string &riderLastName, + const std::string &riderPhoneNumber); + + //getters & setters + const std::string& getFirstName() const; + const std::string& getLastName() const; + const std::string& getGender() const; + int getAge() const; + const std::string& getPhoneNumber() const; + double getRating() const; + double getLatitude() const; + double getLongitude() const; + const std::string& getVehicleType() const; + const std::string& getCurrentState() const; + const std::string& getRiderFirstName() const; + const std::string& getRiderLastName() const; + const std::string& getRiderPhoneNumber() const; + + void setCurrentState(const std::string &state); + void setRiderInfo(const std::string &rf, const std::string &rl, const std::string &rp); + //return a string representation of the driver + std::string toFileString() const; +}; + +#endif +``` + +### Driver.cpp + +```cpp +#include "Driver.h" +#include + +Driver::Driver() : age(0), rating(0.0), latitude(0.0), longitude(0.0) {} + +Driver::Driver(const std::string &fName, const std::string &lName, + const std::string &gen, int a, const std::string &phone, + double r, double lat, double lon, + const std::string &vehType, const std::string &state, + const std::string &rF, const std::string &rL, + const std::string &rP) + : firstName(fName), lastName(lName), gender(gen), age(a), + phoneNumber(phone), rating(r), latitude(lat), longitude(lon), + vehicleType(vehType), currentState(state), + riderFirstName(rF), riderLastName(rL), riderPhoneNumber(rP) {} + +//getters +const std::string& Driver::getFirstName() const { return firstName; } +const std::string& Driver::getLastName() const { return lastName; } +const std::string& Driver::getGender() const { return gender; } +int Driver::getAge() const { return age; } +const std::string& Driver::getPhoneNumber() const { return phoneNumber; } +double Driver::getRating() const { return rating; } +double Driver::getLatitude() const { return latitude; } +double Driver::getLongitude() const { return longitude; } +const std::string& Driver::getVehicleType() const { return vehicleType; } +const std::string& Driver::getCurrentState() const { return currentState; } +const std::string& Driver::getRiderFirstName() const { return riderFirstName; } +const std::string& Driver::getRiderLastName() const { return riderLastName; } +const std::string& Driver::getRiderPhoneNumber() const { return riderPhoneNumber; } + +//setters +void Driver::setCurrentState(const std::string &state) { + currentState = state; +} + +void Driver::setRiderInfo(const std::string &rf, const std::string &rl, const std::string &rp) { + riderFirstName = rf; + riderLastName = rl; + riderPhoneNumber = rp; +} + +std::string Driver::toFileString() const { + //Sandra + //Huang + //Female + //25 + //853-977-5304 + //3.1 + //40.4269 + //-73.0753 + //Standard + //On_the_way_to_pickup + //Michael + //Richard + //445-915-1645 + std::ostringstream oss; + oss << firstName << " " + << lastName << " " + << gender << " " + << age << " " + << phoneNumber << " " + << rating << " " + << latitude << " " + << longitude << " " + << vehicleType << " " + << currentState << " " + << (riderFirstName.empty() ? "null" : riderFirstName) << " " + << (riderLastName.empty() ? "null" : riderLastName) << " " + << (riderPhoneNumber.empty() ? "null" : riderPhoneNumber); + return oss.str(); +} +``` diff --git a/content/zh-cn/posts/csci-1200/hw-2/ride_sharing.7z b/content/zh-cn/posts/csci-1200/hw-2/ride_sharing.7z new file mode 100644 index 0000000000000000000000000000000000000000..3f66834088b94f8b5de705cb2b86f172d75edd56 GIT binary patch literal 45049 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¬^0t%z1KddjY^K>o&X&9jWGQ$ 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 literal 0 HcmV?d00001