Answer To: General guidelines · You may complete this assignment individually or with a partner. · You must not...
Ximi answered on Feb 20 2021
starter_code-2/bill.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
from typing import Dict, Union
class Bill:
""" A single month's bill for a customer's phone line.
A bill keeps track of the number of calls used each month, along with the
corresponding cost per call.
- The billable minutes and the free minutes are incrementally updated as
calls are loaded from the historic data.
- The billing rate per call and the fixed monthly cost depend on the type
of contract.
The bill does not store the amount due. Instead, the amount due can be
computed on demand by the get_cost() method.
=== Public Attributes ===
billed_min:
number of billable minutes used in the month associated with this bill.
free_min:
number of non-billable minutes used in the month associated with this
bill.
min_rate:
cost for one minute of calling
fixed_cost:
fixed costs for the bill (e.g., fixed monthly cost of the
contract, term deposits, etc.)
type:
type of contract
=== Representation Invariants ===
- billed_min >= 0
- free_min >= 0
- min_rate >= 0
- type: "" | "MTM" | "TERM" | "PREPAID"
"""
billed_min: int
free_min: int
min_rate: float
fixed_cost: float
type: str
def __init__(self) -> None:
""" Create a new Bill.
"""
self.billed_min = 0
self.free_min = 0
self.fixed_cost = 0
self.min_rate = 0
self.type = ""
def set_rates(self, contract_type: str, min_cost: float) \
-> None:
""" Set this Bill's contract type to .
Set this Bill's calling rate to .
"""
self.type = contract_type
self.min_rate = min_cost
def add_fixed_cost(self, cost: float) -> None:
""" Add a fixed one-time cost onto the bill.
"""
self.fixed_cost += cost
def add_billed_minutes(self, minutes: int) -> None:
""" Add minutes as billable minutes
"""
self.billed_min += minutes
def add_free_minutes(self, minutes: int) -> None:
""" Add minutes as free minutes
"""
self.free_min += minutes
def get_cost(self) -> float:
""" Return bill amount, considering the rates for billable calls for
this Bill's contract type.
"""
return self.min_rate * self.billed_min + self.fixed_cost
# ----------------------------------------------------------
# NOTE: You do not need to understand the implementation of
# the following method, to be able to solve this assignment
# but feel free to read it to get a sense of what it does.
# ----------------------------------------------------------
def get_summary(self) -> Dict[str, Union[float, int]]:
""" Return a bill summary as a dictionary containing the bill details.
"""
bill_summary = {'type': self.type,
'fixed': self.fixed_cost,
'free_mins': self.free_min,
'billed_mins': self.billed_min,
'min_rate': self.min_rate,
'total': self.get_cost()
}
return bill_summary
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing'
],
'disable': ['R0902'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._bill.py
starter_code-2/callhistory.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
from typing import Dict, List, Tuple
from call import Call
class CallHistory:
"""A class for recording incoming and outgoing calls for a particular number
=== Public Attributes ===
incoming_calls:
Dictionary of incoming calls. Keys are tuples containing a month and a
year, values are a List of Call objects for that month and year.
outgoing_calls:
Dictionary of outgoing calls. Keys are tuples containing a month and a
year, values are a List of Call objects for that month and year.
"""
incoming_calls: Dict[Tuple[int, int], List[Call]]
outgoing_calls: Dict[Tuple[int, int], List[Call]]
def __init__(self) -> None:
""" Create an empty CallHistory.
"""
self.outgoing_calls = {}
self.incoming_calls = {}
def register_outgoing_call(self, call: Call) -> None:
""" Register a Call into this outgoing call history
"""
# TODO: Implement this method. # i have already done it not sure if its right
if self.outgoing_calls == {}:
self.outgoing_calls[call.get_bill_date()[0]] = [call]
elif call.get_bill_date()[0] in self.outgoing_calls.keys():
self.outgoing_calls[call.get_bill_date()[0]].append(call)
def register_incoming_call(self, call: Call) -> None:
""" Register a Call into this incoming call history
"""
# TODO: Implement this method. # i have already done it not sure if its right
if self.incoming_calls == {}:
self.incoming_calls[call.get_bill_date()[0]] = [call]
elif call.get_bill_date()[0] in self.incoming_calls.keys():
self.incoming_calls[call.get_bill_date()[0]].append(call)
# ----------------------------------------------------------
# NOTE: You do not need to understand the implementation of
# the following methods, to be able to solve this assignment
# but feel free to read them to get a sense of what these do.
# ----------------------------------------------------------
def get_monthly_history(self, month: int = None, year: int = None) -> \
Tuple[List[Call], List[Call]]:
""" Return all outgoing and incoming calls for and ,
as a Tuple containing two lists in the following order:
(outgoing calls, incoming calls)
If and are both None, then return all calls from this
call history.
Precondition:
- and are either both specified, or are both missing/None
- if and are specified (non-None), they are both valid
monthly cycles according to the input dataset
"""
monthly_history = ([], [])
if month is not None and year is not None:
if (month, year) in self.outgoing_calls:
for call in self.outgoing_calls[(month, year)]:
monthly_history[0].append(call)
if (month, year) in self.incoming_calls:
for call in self.incoming_calls[(month, year)]:
monthly_history[1].append(call)
else:
for entry in self.outgoing_calls:
for call in self.outgoing_calls[entry]:
monthly_history[0].append(call)
for entry in self.incoming_calls:
for call in self.incoming_calls[entry]:
monthly_history[1].append(call)
return monthly_history
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'datetime', 'call'
''
],
'disable': ['R0902', 'R0913'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._callhistory.py
starter_code-2/StarterCodeArchitecture.pdf
__MACOSX/starter_code-2/._StarterCodeArchitecture.pdf
starter_code-2/__pycache__/customer.cpython-37.pyc
starter_code-2/__pycache__/callhistory.cpython-37.pyc
starter_code-2/__pycache__/call.cpython-37.pyc
__MACOSX/starter_code-2/__pycache__/._call.cpython-37.pyc
starter_code-2/__pycache__/application.cpython-37.pyc
__MACOSX/starter_code-2/__pycache__/._application.cpython-37.pyc
starter_code-2/__pycache__/bill.cpython-37.pyc
__MACOSX/starter_code-2/__pycache__/._bill.cpython-37.pyc
starter_code-2/__pycache__/filter.cpython-37.pyc
starter_code-2/__pycache__/phoneline.cpython-37.pyc
starter_code-2/__pycache__/visualizer.cpython-37.pyc
__MACOSX/starter_code-2/__pycache__/._visualizer.cpython-37.pyc
starter_code-2/__pycache__/contract.cpython-37.pyc
__MACOSX/starter_code-2/.___pycache__
starter_code-2/application.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import datetime
import json
from typing import List, Dict
from visualizer import Visualizer
from customer import Customer
from phoneline import PhoneLine
from call import Call
from contract import PrepaidContract, MTMContract, TermContract
def import_data() -> Dict[str, List[Dict]]:
""" Open the file which stores the json data, and return
a dictionary that stores this data in a format as described in the A1
handout.
Precondition: the dataset file must be in the json format.
"""
log = {}
with open("dataset.json") as o:
log = json.load(o)
return log
def create_customers(log: Dict[str, List[Dict]]) -> List[Customer]:
""" Returns a list of Customer instances for each customer from the input
dataset from the dictionary .
Precondition:
- The dictionary contains the input data in the correct format,
matching the expected input format described in the handout.
"""
customer_list = []
for cust in log['customers']:
customer = Customer(cust['id'])
for line in cust['lines']:
contract = None
# TODO:
# 1) Uncomment the piece of code below once you've implemented
# all types of contracts.
# 2) Make sure to import the necessary contract classes in this file
# 3) Remove this TODO list when you're done.
if line['contract'] == 'prepaid':
# start with $100 credit on the account
contract = PrepaidContract(datetime.date(2017, 12, 25), 100)
elif line['contract'] == 'mtm':
contract = MTMContract(datetime.date(2017, 12, 25))
elif line['contract'] == 'term':
contract = TermContract(datetime.date(2017, 12, 25),
datetime.date(2019, 6, 25))
else:
print("ERROR: unknown contract type")
line = PhoneLine(line['number'], contract)
customer.add_phone_line(line)
customer_list.append(customer)
return customer_list
def find_customer_by_number(number: str, customer_list: List[Customer]) \
-> Customer:
""" Return the Customer with the phone number in the list of
customers .
If the number does not belong to any customer, return None.
"""
cust = None
for customer in customer_list:
if number in customer:
cust = customer
return cust
def new_month(customer_list: List[Customer], month: int, year: int) -> None:
""" Advance all customers in to a new month of their
contract, as specified by the and arguments.
"""
for cust in customer_list:
cust.new_month(month, year)
def process_event_history(log: Dict[str, List[Dict]],
customer_list: List[Customer]) -> None:
""" Process the calls from the dictionary. The
list contains all the customers that exist in the dictionary.
Construct Call objects from and register the Call into the
corresponding customer's call history.
Hint: You must advance all customers to a new month using the new_month()
function, everytime a new month is detected for the current event you are
extracting.
Preconditions:
- All calls are ordered chronologically (based on the call's date and time),
when retrieved from the dictionary , as specified in the handout.
- The argument guarantees that there is no "gap" month with zero
activity for ALL customers, as specified in the handout.
- The dictionary is in the correct format, as defined in the
handout.
- The already contains all the customers from the .
"""
# TODO: Implement this method. We are giving you the first few lines of code
billing_date = datetime.datetime.strptime(log['events'][0]['time'],
"%Y-%m-%d %H:%M:%S")
billing_month = billing_date.month
# start recording the bills from this date
# Note: uncomment the following lines when you're ready to implement this
new_month(customer_list, billing_date.month, billing_date.year)
for event_data in log['events']:
if event_data['type'] == "call":
time = datetime.datetime.strptime(event_data['time'],
"%Y-%m-%d %H:%M:%S")
calls = Call(event_data['src_number'],event_data['dst_number'],time,
event_data['duration'],tuple(event_data['src_loc']),
tuple(event_data['dst_loc']))
caller = find_customer_by_number(event_data['src_number'], customer_list)
receiver = find_customer_by_number(event_data['dst_number'], customer_list)
caller.make_call(calls)
receiver.receive_call(calls)
if __name__ == '__main__':
v = Visualizer()
print("Toronto map coordinates:")
print(" Lower-left corner: -79.697878, 43.576959")
print(" Upper-right corner: -79.196382, 43.799568")
input_dictionary = import_data()
customers = create_customers(input_dictionary)
process_event_history(input_dictionary, customers)
# ----------------------------------------------------------------------
# NOTE: You do not need to understand any of the implementation below,
# to be able to solve this assignment. However, feel free to
# read it anyway, just to get a sense of how the application runs.
# ----------------------------------------------------------------------
# Gather all calls to be drawn on screen for filtering, but we only want
# to plot each call only once, so only plot the outgoing calls to screen.
# (Each call is registered as both an incoming and outgoing)
all_calls = []
for c in customers:
hist = c.get_history()
all_calls.extend(hist[0])
print("\n-----------------------------------------")
print("Total Calls in the dataset:", len(all_calls))
# Main loop for the application.
# 1) Wait for user interaction with the system and processes everything
# appropriately
# 2) Take the calls from the results of the filtering and create the
# drawables and connection lines for those calls
# 3) Display the calls in the visualization window
events = all_calls
while not v.has_quit():
events = v.handle_window_events(customers, events)
connections = []
drawables = []
for event in events:
connections.append(event.get_connection())
drawables.extend(event.get_drawables())
# Put the connections on top of the other sprites
drawables.extend(connections)
v.render_drawables(drawables)
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'json', 'datetime',
'visualizer', 'customer', 'call', 'contract', 'phoneline'
],
'allowed-io': [
'create_customers', 'import_data'
],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._application.py
starter_code-2/phoneline.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
from typing import List, Dict, Tuple, Optional, Union
from call import Call
from callhistory import CallHistory
from bill import Bill
from contract import Contract
class PhoneLine:
""" MewbileTech customer's phone line.
=== Public Attributes ===
number:
phone number
contract:
current contract for this phone, represented by a Contract instance
bills:
dictionary containing all the bills for this phoneline
each key is a (month, year) tuple and the corresponding value is
the Bill object for that month+year date.
callhistory:
call history for this phone line, represented as a CallHistory object
=== Representation Invariants ===
- the dictionary contains as keys only those month+year combinations
for dates that are encountered at least in one call from the input dataset.
"""
number: str
contract: Contract
bills: Dict[Tuple[int, int], Bill]
callhistory: CallHistory
def __init__(self, number: str, contract: Contract) -> None:
""" Create a new PhoneLine with and .
"""
self.number = number
self.contract = contract
self.callhistory = CallHistory()
self.bills = {}
def new_month(self, month: int, year: int) -> None:
""" Advance to a new month (specified by and ) in the
contract corresponding to this phone line.
If the new month+year does not already exist in the attribute,
create a new bill.
"""
if (month, year) not in self.bills:
self.bills[(month, year)] = Bill()
self.contract.new_month(month, year, self.bills[(month, year)])
def make_call(self, call: Call) -> None:
""" Add the to this phone line's callhistory, and bill it
according to the contract for this phone line.
If there is no bill for the current monthly billing cycle, then a new
month must be by advancing to the right month from .
"""
# TODO: Implement this method
self.callhistory.register_outgoing_call(call)
dates = call.get_bill_date()
if self.get_bill(dates[0],dates[1]) == None:
self.new_month(dates[0],dates[1])
def receive_call(self, call: Call) -> None:
""" Add the to this phone line's callhistory.
Incoming calls are not billed under any contract.
However, if there is no bill for the current monthly billing cycle,
then a new month must be by advancing to the right month from
.
"""
# TODO: Implement this method
self.callhistory.register_incoming_call(call)
dates = call.get_bill_date()
if self.get_bill(dates[0],dates[1]) == None:
self.new_month(dates[0],dates[1])
def cancel_line(self) -> float:
""" Cancel this line's contract and return the outstanding bill amount
"""
return self.contract.cancel_contract()
# ----------------------------------------------------------
# NOTE: You do not need to understand the implementation of
# the following methods, to be able to solve this assignment
# but feel free to read them to get a sense of what these do.
# ----------------------------------------------------------
def get_number(self) -> str:
""" Return the phone number for this line
"""
return self.number
def get_call_history(self) -> CallHistory:
""" Return the CallHistory for this line
"""
return self.callhistory
def get_monthly_history(self, month: int = None, year: int = None) -> \
Tuple[List[Call], List[Call]]:
""" Return all calls this line has made during the month of the
year, formatted as a Tuple containing two lists, in this order:
outgoing calls, incoming calls
If month and year are both None, then return all calls from the
callhistory of this phone line.
Precondition:
- and are either both specified, or are both missing/None
- if and are specified (non-None), they are both valid
monthly cycles according to the input dataset
"""
return self.callhistory.get_monthly_history(month, year)
def get_bill(self, month: int, year: int) \
-> Optional[Dict[str, Union[float, int]]]:
""" Return a bill summary for the + billing cycle, as a
dictionary.
This dictionary will include the following string keys:
"number" - indicates the phone number
"type" - indicates the contract type
"fixed" - fixed cost for that month
"free_mins" - number of free minutes used in this monthly cycle
"billed_mins" - number of billed minutes used in this monthly cycle
"min_rate" - billing rate per minute
"total" - total cost for this monthly bill
The values corresponding to each key represent the respective amounts.
If no bill exists for this month+year, return None.
"""
if (month, year) not in self.bills:
return None
bill_summary = self.bills[(month, year)].get_summary()
bill_summary['number'] = self.number
return bill_summary
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing',
'call', 'callhistory', 'bill', 'contract'
],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._phoneline.py
starter_code-2/filter.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import time
import datetime
from typing import List, Tuple
from call import Call
from customer import Customer
class Filter:
""" A class for filtering customer data on some criterion. A filter is
applied to a set of calls.
This is an abstract class. Only subclasses should be instantiated.
"""
def __init__(self) -> None:
pass
def apply(self, customers: List[Customer],
data: List[Call],
filter_string: str) \
-> List[Call]:
""" Return a list of all calls from , which match the filter
specified in .
The is provided by the user through the visual prompt,
after selecting this filter.
The is a list of all customers from the input dataset.
If the filter has
no effect or the is invalid then return the same calls
from the input.
Precondition:
- contains the list of all customers from the input dataset
- all calls included in are valid calls from the input dataset
"""
raise NotImplementedError
def __str__(self) -> str:
""" Return a description of this filter to be displayed in the UI menu
"""
raise NotImplementedError
class ResetFilter(Filter):
"""
A class for resetting all previously applied filters, if any.
"""
def apply(self, customers: List[Customer],
data: List[Call],
filter_string: str) \
-> List[Call]:
""" Reset all of the applied filters. Return a List containing all the
calls corresponding to .
The and arguments for this type of filter are
ignored.
Precondition:
- contains the list of all customers from the input dataset
"""
filtered_calls = []
for c in customers:
customer_history = c.get_history()
# only take outgoing calls, we don't want to include calls twice
filtered_calls.extend(customer_history[0])
return filtered_calls
def __str__(self) -> str:
""" Return a description of this filter to be displayed in the UI menu
"""
return "Reset all of the filters applied so far, if any"
class CustomerFilter(Filter):
"""
A class for selecting only the calls from a given customer.
"""
def apply(self, customers: List[Customer],
data: List[Call],
filter_string: str) \
-> List[Call]:
""" Return a list of all calls from made or received by the
customer with the id specified in .
The list contains all customers from the input dataset.
The filter string is valid if and only if it contains a valid
customer ID.
- If the filter string is invalid, return the original list
- If the filter string is invalid, your code must not crash, as
specified in the handout.
"""
filtered_calls = []
c_ids = [c._id for c in customers]
if filter_string not in c_ids:
return data
else:
for c in customers:
if filter_string == c._id:
customer_history = c.get_history()
# only take outgoing calls, we don't want to include calls twice
if customer_history[0] in data:
filtered_calls.extend(customer_history[0])
return filtered_calls
def __str__(self) -> str:
""" Return a description of this filter to be displayed in the UI menu
"""
return "Filter events based on customer ID"
class DurationFilter(Filter):
"""
A class for selecting only the calls lasting either over or under a
specified duration.
"""
def apply(self, customers: List[Customer],
data: List[Call],
filter_string: str) \
-> List[Call]:
""" Return a list of all calls from with a duration of under or
over the time indicated in the .
The list contains all customers from the input dataset.
The filter string is valid if and only if it contains the following
input format: either "Lxxx" or "Gxxx", indicating to filter calls less
than xxx or greater than xxx seconds, respectively.
- If the filter string is invalid, return the original list
- If the filter string is invalid, your code must not crash, as
specified in the handout.
"""
filtered_calls = []
if not filter_string.startswith('L') or not filter_string.startswith('G'):
return data
elif filter_string.startswith('L'):
for call in data:
if call.duration < int(filter_string.split('L')[1]):
filtered_calls.extend(call)
elif filter_string.startswith('G'):
if call.duration > int(filter_string.split('G')[1]):
filtered_calls.extend(call)
return filtered_calls
def __str__(self) -> str:
""" Return a description of this filter to be displayed in the UI menu
"""
return "Filter calls based on duration; " \
"L### returns calls less than specified length, G### for greater"
class LocationFilter(Filter):
"""
A class for selecting only the calls that took place within a specific area
"""
def apply(self, customers: List[Customer],
data: List[Call],
filter_string: str) \
-> List[Call]:
""" Return a list of all calls from , which took place within
a location specified by the (at least the source or the
destination of the event was in the range of coordinates from the
).
The list contains all customers from the input dataset.
The filter string is valid if and only if it contains four valid
coordinates within the map boundaries.
These coordinates represent the location of the lower left corner
and the upper right corner of the search location rectangle,
as 2 pairs of longitude/latitude coordinates, each separated by
a comma and a space:
lowerLong, lowerLat, upperLong, upperLat
Calls that fall exactly on the boundary of this rectangle are
considered a match as well.
- If the filter string is invalid, return the original list
- If the filter string is invalid, your code must not crash, as
specified in the handout.
"""
filtered_calls = []
if len(filter_string.split(',')) < 4:
return data
else:
coords = map(int, filter_string.split(','))
for call in data:
lat, lng = call.src_loc
if lng > coords[0] and lat > coords[1] and lng < coords[2] \
and lat < coords[3]:
filtered_calls.extend(call)
return data
def __str__(self) -> str:
""" Return a description of this filter to be displayed in the UI menu
"""
return "Filter calls made or received in a given rectangular area. " \
"Format: \"lowerLong, lowerLat, " \
"upperLong, upperLat\" (e.g., -79.6, 43.6, -79.3, 43.7)"
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'time', 'datetime', 'call', 'customer'
],
'max-nested-blocks': 4,
'allowed-io': ['apply', '__str__'],
'disable': ['W0611', 'W0703'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._filter.py
starter_code-2/customer.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
from typing import List, Union, Tuple, Dict
from phoneline import PhoneLine
from call import Call
from callhistory import CallHistory
class Customer:
""" A MewbileTech customer.
"""
# === Private Attributes ===
# _id:
# this customer's 4 digit Customer id
# _phone_lines:
# this customer's phone lines
_id: int
_phone_lines: List[PhoneLine]
def __init__(self, cid: int) -> None:
""" Create a new Customer with the id
"""
self._id = cid
self._phone_lines = []
def new_month(self, month: int, year: int) -> None:
""" Advance to a new month (specified by and ) in the
contracts for each phone line that this customer owns.
Note: we don't care about payments; we assume that this customer pays
the bill amount in full for the previous month.
"""
for line in self._phone_lines:
line.new_month(month, year)
def make_call(self, call: Call) -> None:
""" Record that a call was made from the source phone number of .
Precondition: The phone line associated with the source phone number of
, is owned by this customer
"""
# TODO: Implement this method
for phone_line in self._phone_lines:
if phone_line.number == call.src_number:
phone_line.make_call(call)
def receive_call(self, call: Call) -> None:
""" Record that a call was made to the destination phone number of
.
Precondition: The phone line associated with the destination phone
number of , is owned by this customer
"""
# TODO: Implement this method
for phone_line in self._phone_lines:
if phone_line.number == call.dst_number:
phone_line.receive_call(call)
def cancel_phone_line(self, number: str) -> Union[float, None]:
""" Remove PhoneLine with number from this customer and return
the amount still owed by this customer.
Return None if is not owned by this customer.
"""
fee = None
for pl in self._phone_lines:
if pl.get_number() == number:
self._phone_lines.remove(pl)
fee = pl.cancel_line()
return fee
# ----------------------------------------------------------
# NOTE: You do not need to understand the implementation of
# the following methods, to be able to solve this assignment
# but feel free to read them to get a sense of what these do.
# ----------------------------------------------------------
def add_phone_line(self, pline: PhoneLine) -> None:
""" Add a new PhoneLine to this customer.
"""
self._phone_lines.append(pline)
def get_phone_numbers(self) -> List[str]:
""" Return a list of all of the numbers this customer owns
"""
numbers = []
for line in self._phone_lines:
numbers.append(line.get_number())
return numbers
def get_id(self) -> int:
""" Return the id for this customer
"""
return self._id
def __contains__(self, item: str) -> bool:
""" Check if this customer owns the phone number
"""
contains = False
for line in self._phone_lines:
if line.get_number() == item:
contains = True
return contains
def generate_bill(self, month: int, year: int) \
-> Tuple[int, float, List[Dict]]:
""" Return a bill summary for the and billing cycle,
as a Tuple containing the customer id, total cost for all phone lines,
and a List of bill summaries generated for each phone line.
"""
bills = []
total = 0
for l in self._phone_lines:
line_bill = l.get_bill(month, year)
if line_bill is not None:
bills.append(line_bill)
total += line_bill['total']
return self._id, total, bills
def print_bill(self, month: int, year: int) -> None:
""" Print the bill for the and billing cycle, to the
console.
Precondition:
- and correspond to a valid bill for this customer.
That is, the month and year cannot be outside the range of the historic
records from the input dataset.
"""
bill_data = self.generate_bill(month, year)
print("========= BILL ===========")
print("Customer id: " + str(self._id) + " month: " +
str(month) + "/" + str(year))
print("Total due this month: {0:.2f}".format(bill_data[1]))
for line in bill_data[2]:
print("\tnumber: " + line['number'] + " type: " + line['type'])
print("==========================")
def get_history(self) \
-> Tuple[List[Call], List[Call]]:
""" Return all the calls from the call history of this
customer, as a tuple in the following format:
(outgoing calls, incoming calls)
"""
history = ([], [])
for line in self._phone_lines:
line_history = line.get_monthly_history()
history[0].extend(line_history[0])
history[1].extend(line_history[1])
return history
def get_call_history(self, number: str = None) -> List[CallHistory]:
""" Return the call history for , stored into a list.
If is not provided, return a list of all call histories for all
phone lines owned by this customer.
"""
history = []
for line in self._phone_lines:
if number is not None:
if line.get_number() == number:
history.append(line.get_call_history())
else:
history.append(line.get_call_history())
return history
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'phoneline', 'call', 'callhistory'
],
'allowed-io': ['print_bill'],
'disable': ['R0902', 'R0913'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._customer.py
starter_code-2/call.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import datetime
import os
from typing import Tuple, List, Optional
import pygame
# Sprite files to display the start and end of a call
START_CALL_SPRITE = 'data/call-start-2.png'
END_CALL_SPRITE = 'data/call-end-2.png'
# ----------------------------------------------------------------------------
# NOTE: You do not need to understand the implementation of the Drawable class
# to be able to solve this assignment. However, feel feel free to read it for
# the fun of understanding the visualization system.
# ----------------------------------------------------------------------------
class Drawable:
"""A class for objects that the graphical renderer can draw.
=== Public Attributes ===
sprite:
image object for this drawable or None.
If none, then must have linelimits
linelimits:
limits for the line of the connection or None.
If none, then must have sprite
loc: location (longitude/latitude pair)
"""
sprite: Optional[pygame.Surface]
linelimits: Optional[Tuple[float, float]]
loc: Optional[Tuple[float, float]]
def __init__(self, sprite_file: Optional[str] = None,
location: Optional[Tuple[float, float]] = None,
linelimits: Optional[Tuple[Tuple[float, float],
Tuple[float, float]]] = None) \
-> None:
"""Initialize this drawable object with the ,
and .
"""
self.linelimits = None
self.sprite = None
self.loc = None
if sprite_file is not None and location is not None:
self.sprite = pygame.transform.smoothscale(
pygame.image.load(os.path.join(os.path.dirname(__file__),
sprite_file)), (13, 13))
self.loc = location
else:
self.linelimits = linelimits
def get_position(self) -> Tuple[float, float]:
"""Return the (long, lat) position of this object at the given time.
"""
return self.loc
def get_linelimits(self) -> Optional[Tuple[float, float]]:
"""Return the limits for the line if the drawable is a line type
(otherwise None)
"""
return self.linelimits
class Call:
""" A call made by a customer to another customer.
=== Public Attributes ===
src_number:
source number for this Call
dst_number:
destination number for this Call
time:
date and time of this Call
duration:
duration in seconds for this Call
src_loc:
location of the source of this Call; a Tuple containing the longitude
and latitude coordinates
dst_loc:
location of the destination of this Call; a Tuple containing the
longitude and latitude coordinates
drawables:
sprites for drawing the source and destination of this Call
connection:
connecting line between the two sprites representing the source and
destination of this Call
=== Representation Invariants ===
- duration >= 0
"""
src_number: str
dst_number: str
time: datetime.datetime
duration: int
src_loc: Tuple[float, float]
dst_loc: Tuple[float, float]
drawables: List[Drawable]
connection: Drawable
def __init__(self, src_nr: str, dst_nr: str,
calltime: datetime.datetime, duration: int,
src_loc: Tuple[float, float], dst_loc: Tuple[float, float]) \
-> None:
""" Create a new Call object with the given parameters.
"""
self.src_number = src_nr
self.dst_number = dst_nr
self.time = calltime
self.duration = duration
self.src_loc = src_loc
self.dst_loc = dst_loc
self.drawables = [Drawable(sprite_file=START_CALL_SPRITE,
location=src_loc),
Drawable(sprite_file=END_CALL_SPRITE,
location=dst_loc)]
self.connection = Drawable(linelimits=(src_loc, dst_loc))
def get_bill_date(self) -> Tuple[int, int]:
""" Return the billing date for this Call, as a tuple containing the
month and the year
"""
return self.time.month, self.time.year
# ----------------------------------------------------------
# NOTE: You do not need to understand the implementation of
# the following methods, to be able to solve this assignment
# but feel free to read them to get a sense of what these do.
# ----------------------------------------------------------
def get_drawables(self) -> List[Drawable]:
""" Return the list of drawable sprites for this Call
"""
return self.drawables
def get_connection(self) -> Drawable:
""" Return the connecting line for this Call start and end locations
"""
return self.connection
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'datetime', 'os', 'pygame'
],
'disable': ['R0902', 'R0913'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._call.py
starter_code-2/contract.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import datetime
from math import ceil
from typing import Optional
from bill import Bill
from call import Call
# Constants for the month-to-month contract monthly fee and term deposit
MTM_MONTHLY_FEE = 50.00
TERM_MONTHLY_FEE = 20.00
TERM_DEPOSIT = 300.00
# Constants for the included minutes and SMSs in the term contracts (per month)
TERM_MINS = 100
# Cost per minute and per SMS in the month-to-month contract
MTM_MINS_COST = 0.05
# Cost per minute and per SMS in the term contract
TERM_MINS_COST = 0.1
# Cost per minute and per SMS in the prepaid contract
PREPAID_MINS_COST = 0.025
class Contract:
""" A contract for a phone line
This is an abstract class. Only subclasses should be instantiated.
=== Public Attributes ===
start:
starting date for the contract
bill:
bill for this contract for the last month of call records loaded from
the input dataset
"""
start: datetime.datetime
bill: Optional[Bill]
def __init__(self, start: datetime.date) -> None:
""" Create a new Contract with the date, starts as inactive
"""
self.start = start
self.bill = None
def new_month(self, month: int, year: int, bill: Bill) -> None:
""" Advance to a new month in the contract, corresponding to and
. This may be the first month of the contract.
Store the argument in this contract and set the appropriate rate
per minute and fixed cost.
"""
raise NotImplementedError
def bill_call(self, call: Call) -> None:
""" Add the to the bill.
Precondition:
- a bill has already been created for the month+year when the
was made. In other words, you can safely assume that self.bill has been
already advanced to the right month+year.
"""
self.bill.add_billed_minutes(ceil(call.duration / 60.0))
def cancel_contract(self) -> float:
""" Return the amount owed in order to close the phone line associated
with this contract.
Precondition:
- a bill has already been created for the month+year when this contract
is being cancelled. In other words, you can safely assume that self.bill
exists for the right month+year when the cancelation is requested.
"""
self.start = None
return self.bill.get_cost()
# TODO: Implement the MTMContract, TermContract, and PrepaidContract
class TermContract(Contract):
def __init__(self, start: datetime.date, end: datetime.date) -> None:
self.start = end
self.end = end
Contract.__init__(self, start)
def new_month(self, month: int, year: int, bill: Bill) -> None:
""" Advance to a new month in the contract, corresponding to and
. This may be the first month of the contract.
Store the argument in this contract and set the appropriate rate
per minute and fixed cost.
"""
self.bill = bill
self.bill.set_rates('TERM', TERM_MINS_COST)
self.bill.add_fixed_cost(TERM_DEPOSIT)
self.bill.add_free_minutes(TERM_MINS)
class MTMContract(Contract):
def __init__(self, start: datetime.date) -> None:
self.start = start
Contract.__init__(self, start)
def new_month(self, month: int, year: int, bill: Bill) -> None:
""" Advance to a new month in the contract, corresponding to and
. This may be the first month of the contract.
Store the argument in this contract and set the appropriate rate
per minute and fixed cost.
"""
self.bill = bill
self.bill.set_rates('MTM', MTM_MINS_COST)
self.bill.add_fixed_cost(MTM_MONTHLY_FEE)
class PrepaidContract(Contract):
def __init__(self, start: datetime.date, credit) -> None:
self.start = start
self.credit = credit
Contract.__init__(self, start)
def new_month(self, month: int, year: int, bill: Bill) -> None:
""" Advance to a new month in the contract, corresponding to and
. This may be the first month of the contract.
Store the argument in this contract and set the appropriate rate
per minute and fixed cost.
"""
self.bill = bill
self.bill.set_rates('PREPAID', PREPAID_MINS_COST)
self.bill.add_fixed_cost(self.credit)
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'python_ta', 'typing', 'datetime', 'bill', 'call', 'math'
],
'disable': ['R0902', 'R0913'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._contract.py
starter_code-2/data/call-end-2.png
__MACOSX/starter_code-2/data/._call-end-2.png
starter_code-2/data/call-start-2.png
__MACOSX/starter_code-2/data/._call-start-2.png
starter_code-2/data/toronto_map.png
__MACOSX/starter_code-2/data/._toronto_map.png
starter_code-2/data/call-end.png
__MACOSX/starter_code-2/data/._call-end.png
starter_code-2/data/call-start.png
__MACOSX/starter_code-2/data/._call-start.png
__MACOSX/starter_code-2/._data
starter_code-2/sample_tests.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import datetime
import pytest
from application import create_customers, process_event_history
from customer import Customer
from contract import TermContract, MTMContract, PrepaidContract
from phoneline import PhoneLine
from filter import DurationFilter, CustomerFilter, ResetFilter
"""
This is a sample test file with a limited set of cases, which are similar in
nature to the full autotesting suite
Use this framework to check some of your work and as a starting point for
creating your own tests
*** Passing these tests does not mean that it will necessarily pass the
autotests ***
"""
def create_single_customer_with_all_lines() -> Customer:
""" Create a customer with one of each type of PhoneLine
"""
contracts = [
TermContract(start=datetime.date(year=2017, month=12, day=25),
end=datetime.date(year=2019, month=6, day=25)),
MTMContract(start=datetime.date(year=2017, month=12, day=25)),
PrepaidContract(start=datetime.date(year=2017, month=12, day=25),
balance=100)
]
numbers = ['867-5309', '273-8255', '649-2568']
customer = Customer(cid=5555)
for i in range(len(contracts)):
customer.add_phone_line(PhoneLine(numbers[i], contracts[i]))
customer.new_month(12, 2017)
return customer
test_dict = {'events': [
{"type": "sms",
"src_number": "867-5309",
"dst_number": "273-8255",
"time": "2018-01-01 01:01:01",
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "sms",
"src_number": "273-8255",
"dst_number": "649-2568",
"time": "2018-01-01 01:01:02",
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "sms",
"src_number": "649-2568",
"dst_number": "867-5309",
"time": "2018-01-01 01:01:03",
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "call",
"src_number": "273-8255",
"dst_number": "867-5309",
"time": "2018-01-01 01:01:04",
"duration": 10,
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "call",
"src_number": "867-5309",
"dst_number": "649-2568",
"time": "2018-01-01 01:01:05",
"duration": 50,
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "call",
"src_number": "649-2568",
"dst_number": "273-8255",
"time": "2018-01-01 01:01:06",
"duration": 50,
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]}
],
'customers': [
{'lines': [
{'number': '867-5309',
'contract': 'term'},
{'number': '273-8255',
'contract': 'mtm'},
{'number': '649-2568',
'contract': 'prepaid'}
],
'id': 5555}
]
}
def test_customer_creation() -> None:
""" Test for the correct creation of Customer, PhoneLine, and Contract
classes
"""
customer = create_single_customer_with_all_lines()
bill = customer.generate_bill(12, 2017)
assert len(customer.get_phone_numbers()) == 3
assert len(bill) == 3
assert bill[0] == 5555
assert bill[1] == 270.0
assert len(bill[2]) == 3
assert bill[2][0]['total'] == 320
assert bill[2][1]['total'] == 50
assert bill[2][2]['total'] == -100
# Check for the customer creation in application.py
customer = create_customers(test_dict)[0]
customer.new_month(12, 2017)
bill = customer.generate_bill(12, 2017)
assert len(customer.get_phone_numbers()) == 3
assert len(bill) == 3
assert bill[0] == 5555
assert bill[1] == 270.0
assert len(bill[2]) == 3
assert bill[2][0]['total'] == 320
assert bill[2][1]['total'] == 50
assert bill[2][2]['total'] == -100
def test_events() -> None:
""" Test the ability to make calls, and ensure that the CallHistory objects
are populated
"""
customers = create_customers(test_dict)
customers[0].new_month(1, 2018)
process_event_history(test_dict, customers)
# Check the bill has been computed correctly
bill = customers[0].generate_bill(1, 2018)
assert bill[0] == 5555
assert bill[1] == pytest.approx(-29.925)
assert bill[2][0]['total'] == pytest.approx(20)
assert bill[2][0]['free_mins'] == 1
assert bill[2][1]['total'] == pytest.approx(50.05)
assert bill[2][1]['billed_mins'] == 1
assert bill[2][2]['total'] == pytest.approx(-99.975)
assert bill[2][2]['billed_mins'] == 1
# Check the CallHistory objects are populated
history = customers[0].get_call_history('867-5309')
assert len(history) == 1
assert len(history[0].incoming_calls) == 1
assert len(history[0].outgoing_calls) == 1
history = customers[0].get_call_history()
assert len(history) == 3
assert len(history[0].incoming_calls) == 1
assert len(history[0].outgoing_calls) == 1
def test_contract_start_dates() -> None:
""" Test the start dates of the contracts.
Ensure that the start dates are the correct dates as specified in the given
starter code.
"""
customers = create_customers(test_dict)
for c in customers:
for pl in c._phone_lines:
assert pl.contract.start == datetime.date(year=2017, month=12, day=25)
if hasattr(pl.contract, 'end'): # only check if there is an end date (TermContract)
assert pl.contract.end == datetime.date(year=2019, month=6, day=25)
def test_filters() -> None:
""" Test the functionality of the filters.
We are only giving you a couple of tests here, you should expand both the
dataset and the tests for the different types of applicable filters
"""
customers = create_customers(test_dict)
process_event_history(test_dict, customers)
# Populate the list of calls:
calls = []
hist = customers[0].get_history()
# only consider outgoing calls, we don't want to duplicate calls in the test
calls.extend(hist[0])
# The different filters we are testing
filters = [
DurationFilter(),
CustomerFilter(),
ResetFilter()
]
# These are the inputs to each of the above filters in order.
# Each list is a test for this input to the filter
filter_strings = [
["L50", "G10", "L0", "50", "AA", ""],
["5555", "1111", "9999", "aaaaaaaa", ""],
["rrrr", ""]
]
# These are the expected outputs from the above filter application
# onto the full list of calls
expected_return_lengths = [
[1, 2, 0, 3, 3, 3],
[3, 3, 3, 3, 3],
[3, 3]
]
for i in range(len(filters)):
for j in range(len(filter_strings[i])):
result = filters[i].apply(customers, calls, filter_strings[i][j])
assert len(result) == expected_return_lengths[i][j]
if __name__ == '__main__':
pytest.main(['sample_tests.py'])
__MACOSX/starter_code-2/._sample_tests.py
starter_code-2/data.py
# This is formatted to reveal the structure of the JSON data files.
tiny_data = \
{"events": [
{"type": "sms",
"src_number": "422-4785",
"dst_number": "731-0105",
"time": "2018-01-01 14:29:05",
"src_loc": [-79.42848154284123, 43.641401675960374],
"dst_loc": [-79.52745693913239, 43.750338501653374]},
{"type": "sms",
"src_number": "934-0592",
"dst_number": "136-5226",
"time": "2018-01-02 03:17:57",
"src_loc": [-79.45188229255568, 43.62186408875219],
"dst_loc": [-79.36866519485261, 43.680793196449336]},
{"type": "call",
"src_number": "422-4785",
"dst_number": "136-5226",
"time": "2018-01-03 02:14:31",
"duration": 117,
"src_loc": [-79.68079993411648, 43.64986163420895],
"dst_loc": [-79.46762523704258, 43.59568659654661]}
],
"customers": [
{"lines": [{"number": "861-1710", "contract": "mtm"}], "id": 2247},
{"lines": [{"number": "426-4804", "contract": "term"},
{"number": "934-0592", "contract": "term"},
{"number": "131-3768", "contract": "prepaid"},
{"number": "386-6346", "contract": "term"}], "id": 3895},
{"lines": [{"number": "931-8588", "contract": "term"},
{"number": "981-7145", "contract": "mtm"},
{"number": "817-5571", "contract": "mtm"},
{"number": "581-0057", "contract": "mtm"},
{"number": "452-7360", "contract": "prepaid"}], "id": 8548},
{"lines": [{"number": "895-2223", "contract": "prepaid"},
{"number": "425-5910", "contract": "mtm"},
{"number": "731-0105", "contract": "term"},
{"number": "136-5226", "contract": "mtm"},
{"number": "422-4785", "contract": "prepaid"}], "id": 5716},
{"lines": [{"number": "829-6467", "contract": "term"}], "id": 9701}
]
}
__MACOSX/starter_code-2/._data.py
starter_code-2/pyta_report.html
PyTA Error Report
Tue. Feb. 19 2019, 07:35:45 PM
/Users/maria/Desktop/csc148/assignments/a1/starter_code/callhistory.py
Code Errors or Forbidden Usage (fix: high priority)
Expand/Collapse Section
None!
Style or Convention Errors (fix: before submission)
Expand/Collapse Section
❐ C0301 (line-too-long)
2
occurrences.
Expand/Collapse
[Line 41] Line too long (85/80)
39 """ Register a Call into this outgoing call history
40 """
41 # TODO: Implement this method. # i have already done it not sure if its right
42 if self.outgoing_calls == {}:
43 self.outgoing_calls[call.get_bill_date()] = [call]
[Line 49] Line too long (85/80)
47 """ Register a Call into this incoming call history
48 """
49 # TODO: Implement this method. # i have already done it not sure if its right
50 if self.incoming_calls == {}:
51 self.incoming_calls[call.get_bill_date()] = [call]
Found a bug? Report it to Prof. Liu!
__MACOSX/starter_code-2/._pyta_report.html
starter_code-2/visualizer.py
"""
CSC148, Winter 2019
Assignment 1
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
All of the files in this directory and all subdirectories are:
Copyright (c) 2019 Bogdan Simion, Diane Horton, Jacqueline Smith
"""
import os
import threading
import math
import time
from typing import List, Tuple, Any, Optional, Union, Callable
from tkinter import *
import pygame
from call import Drawable, Call
from customer import Customer
from filter import DurationFilter, CustomerFilter, LocationFilter, ResetFilter
"""
=== Module Description ===
This file contains the Visualizer class, which is responsible for interacting
with Pygame, the graphics library we're using for this assignment.
There's quite a bit in this file, but you aren't responsible for most of it.
It also contains the Map class, which is responsible for converting between
longitude/latitude coordinates and pixel coordinates on the pygame window.
DO NOT CHANGE ANY CODE IN THIS FILE, unless instructed in the handout.
"""
# ----------------------------------------------------------------------------
# NOTE: You do not need to understand any of the visualization details from
# this module, to be able to solve this assignment. However, feel free to read
# it for the fun of understanding the visualization system.
# ----------------------------------------------------------------------------
WHITE = (255, 255, 255)
LINE_COLOUR = (0, 64, 125)
MAP_FILE = 'data/toronto_map.png'
# Map upper-left and bottom-right coordinates (long, lat).
MAP_MIN = (-79.697878, 43.799568)
MAP_MAX = (-79.196382, 43.576959)
# Window size
SCREEN_SIZE = (1000, 700)
class Visualizer:
"""Visualizer for the current state of a simulation.
=== Public attributes ===
r: the Tk object for the main window
"""
# === Private attributes ===
# _screen: the pygame window that is shown to the user.
# _mouse_down: whether the user is holding down a mouse button
# on the pygame window.
# _map: the Map object responsible for converting between longitude/latitude
# coordinates and the pixels of the visualization window.
_uiscreen: pygame.Surface
_screen: pygame.Surface
_mouse_down: bool
_map: 'Map'
_quit: bool
r: Tk
def __init__(self) -> None:
"""Initialize this visualization.
"""
self.r = Tk()
Label(self.r, text="Welcome to MewbileTech phone management system")\
.grid(row=0, column=0)
self.r.title("MewbileTech management system")
pygame.init()
self._uiscreen = pygame.display.set_mode(
(SCREEN_SIZE[0] + 200, SCREEN_SIZE[1]),
pygame.HWSURFACE | pygame.DOUBLEBUF)
# Add the text along the side, displaying the command keys for filters
self._uiscreen.fill((125, 125, 125))
font = pygame.font.SysFont(None, 25)
self._uiscreen.blit(font.render("FILTER KEYBINDS", True, WHITE),
(SCREEN_SIZE[0] + 10, 50))
self._uiscreen.blit(font.render("C: customer ID", True, WHITE),
(SCREEN_SIZE[0] + 10, 100))
self._uiscreen.blit(font.render("D: duration", True, WHITE),
(SCREEN_SIZE[0] + 10, 150))
self._uiscreen.blit(font.render("L: location", True, WHITE),
(SCREEN_SIZE[0] + 10, 200))
self._uiscreen.blit(font.render("R: reset filter", True, WHITE),
(SCREEN_SIZE[0] + 10, 250))
self._uiscreen.blit(font.render("M: monthly bill", True, WHITE),
(SCREEN_SIZE[0] + 10, 650))
self._screen = self._uiscreen.subsurface((0, 0), SCREEN_SIZE)
self._screen.fill(WHITE)
self._mouse_down = False
self._map = Map(SCREEN_SIZE)
# Initial render
self.render_drawables([])
self._quit = False
def render_drawables(self, drawables: List[Drawable]) -> None:
"""Render the to the screen
"""
# Draw the background map onto the screen
self._screen.fill(WHITE)
self._screen.blit(self._map.get_current_view(), (0, 0))
# Add all of the objects onto the screen
self._map.render_objects(drawables, self._screen)
# Show the new image
pygame.display.flip()
def has_quit(self) -> bool:
"""Returns if the program has received the quit command
"""
return self._quit
def handle_window_events(self, customers: List[Customer],
drawables: List[Call]) \
-> List[Call]:
"""Handle any user events triggered through the pygame window.
The are the objects currently displayed, while the
list contains all customers from the input data.
Return a new list of Calls, according to user input actions.
"""
new_drawables = drawables
for event in pygame.event.get():
if event.type == pygame.QUIT:
self._quit = True
elif event.type == pygame.KEYDOWN:
f = None
num_threads = 1
if event.unicode == "d":
f = DurationFilter()
elif event.unicode == "l":
f = LocationFilter()
elif event.unicode == "c":
f = CustomerFilter()
elif event.unicode == "r":
f = ResetFilter()
num_threads = 1
if f is not None:
def result_wrapper(fun: Callable[[List[Customer],
List[Call],
str], List[Call]],
customers: List[Customer],
data: List[Call],
filter_string: str,
res: List) -> None:
"""A final wrapper to return the result of the operation
"""
res.append(fun(customers, data, filter_string))
def threading_wrapper(customers: List[Customer],
data: List[Call],
filter_string: str) -> List[Call]:
"""A wrapper for the application of filters with
threading
"""
chunk_sz_calls = math.ceil(
(len(data) + num_threads - 1) / num_threads)
print("Num_threads:", num_threads)
print("Chunk_calls:", chunk_sz_calls)
threads = []
results = []
for i in range(num_threads):
res = []
results.append(res)
t = threading.Thread(target=result_wrapper,
args=
(f.apply,
customers,
data[i*chunk_sz_calls:
(i+1)*chunk_sz_calls],
filter_string,
res))
t.daemon = True
t.start()
threads.append(t)
# f.apply(customers, data, filter_string)
# Wait to finish
for t in threads:
t.join()
# Now reconstruct the data
new_data = []
for res in results:
new_data.extend(res[0])
return new_data
new_drawables = self.entry_window(str(f),
customers,
drawables,
threading_wrapper)
# Perform the billing for a selected customer:
if event.unicode == "m":
try:
def get_customer(customers: List[Customer],
found_customer: List[Customer],
input_string: str) -> None:
""" A helper to find the customer specified in the
input string appends to the found_customer the
matching customer
"""
try:
for c in customers:
if c.get_id() == int(input_string):
found_customer.append(c)
except ValueError:
pass
customer = []
self.entry_window("Generate the bill for the customer "
"with ID:", customers, customer,
get_customer)
if len(customer) == 0:
raise ValueError
# Just want to return the parsed input string
def get_input_date(customer: List[Customer],
drawables: List[Call],
input_string: str) \
-> Optional[List[int]]:
""" A helper to get the input date """
try:
return [int(s.strip())
for s in input_string.split(',')]
except ValueError:
return None
date = self.entry_window("Bill month and year: "
"month, year",
customers,
drawables,
get_input_date)
if date is None or date == ([], []):
raise ValueError
customer[0].print_bill(date[0], date[1])
except ValueError:
print("ERROR: bad formatting for input string")
except IndexError:
print("Customer not found")
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
self._mouse_down = True
elif event.button == 4:
self._map.zoom(-0.1)
elif event.button == 5:
self._map.zoom(0.1)
elif event.type == pygame.MOUSEBUTTONUP:
self._mouse_down = False
elif event.type == pygame.MOUSEMOTION:
if self._mouse_down:
self._map.pan(pygame.mouse.get_rel())
else:
pygame.mouse.get_rel()
return new_drawables
def entry_window(self, field: str,
customers: List[Customer],
drawables: Union[List[Customer],
List[Call]],
callback: Callable[[List[Customer],
List[Call],
str],
List[Call]]) \
-> Union[List[Call], List[Any]]:
""" Creates a pop-up window for the user to enter input text, and
applies the function onto the
"""
new_drawables = []
m = Tk()
m.title("Filter")
Label(m, text=field).grid(row=0)
el = Entry(m)
# No textbox for filter string if it's a Reset filter
if field != "Reset all of the filters applied so far, if any":
el.grid(row=0, column=1)
# The callback function:
def callback_wrapper(input_string: str) -> None:
""" A wrapper to call the callback function on the
and print the time taken for the function to execute.
"""
nonlocal new_drawables
nonlocal m
t1 = time.time()
new_drawables = callback(customers, drawables, input_string)
t2 = time.time()
print("Time elapsed: " + str(t2 - t1))
m.destroy()
Button(m, text="Apply Filter",
command=lambda:
callback_wrapper(el.get()
if field != "Reset all of the filters applied "
"so far, if any"
else "")).grid(row=1, column=0,
sticky=W, pady=5)
m.mainloop()
print("FILTER APPLIED")
return new_drawables
class Map:
""" Window panning and zooming interface.
=== Public attributes ===
image:
the full image for the area to cover with the map
min_coords:
the minimum long/lat coordinates
max_coords:
the maximum long/lat coordinates
screensize:
the dimensions of the screen
"""
# === Private attributes ===
# _xoffset:
# offset on x axis
# _yoffset:
# offset on y axis
# _zoom:
# map zoom level
image: pygame.image
min_coords: Tuple[float, float]
max_coords: Tuple[float, float]
screensize: Tuple[int, int]
_xoffset: int
_yoffset: int
_zoom: int
def __init__(self, screendims: Tuple[int, int]) -> None:
""" Initialize this map for the given screen dimensions .
"""
self.image = pygame.image.load(
os.path.join(os.path.dirname(__file__), MAP_FILE))
self.min_coords = MAP_MIN
self.max_coords = MAP_MAX
self._xoffset = 0
self._yoffset = 0
self._zoom = 1
self.screensize = screendims
def render_objects(self, drawables: List[Drawable],
screen: pygame.Surface) -> None:
""" Render the onto the .
"""
for drawable in drawables:
longlat_position = drawable.get_position()
if longlat_position is not None:
sprite_position = self._longlat_to_screen(longlat_position)
screen.blit(drawable.sprite, sprite_position)
else: # is a line segment
endpoints = drawable.get_linelimits()
pygame.draw.aaline(screen,
LINE_COLOUR,
self._longlat_to_screen(endpoints[0]),
self._longlat_to_screen(endpoints[1]))
def _longlat_to_screen(self,
location: Tuple[float, float]) -> Tuple[int, int]:
""" Convert the long/lat coordinates into pixel coordinates.
"""
x = round((location[0] - self.min_coords[0]) /
(self.max_coords[0] - self.min_coords[0]) *
self.image.get_width())
y = round((location[1] - self.min_coords[1]) /
(self.max_coords[1] - self.min_coords[1]) *
self.image.get_height())
x = round((x - self._xoffset) * self._zoom * self.screensize[0] /
self.image.get_width())
y = round((y - self._yoffset) * self._zoom * self.screensize[1] /
self.image.get_height())
return x, y
def pan(self, dp: Tuple[int, int]) -> None:
""" Pan the view in the image by (dx, dy) screenspace pixels.
"""
self._xoffset -= dp[0]
self._yoffset -= dp[1]
self._clamp_transformation()
def zoom(self, dx: float) -> None:
""" Zoom the view by amount.
The centre of the zoom is the top-left corner of the visible region.
"""
if (self._zoom >= 4 and dx > 0) or (self._zoom <= 1 and dx < 0):
return
self._zoom += dx
self._clamp_transformation()
def _clamp_transformation(self) -> None:
""" Ensure that the transformation parameters are within a fixed range.
"""
raw_width = self.image.get_width()
raw_height = self.image.get_height()
zoom_width = round(raw_width / self._zoom)
zoom_height = round(raw_height / self._zoom)
self._xoffset = min(raw_width - zoom_width, max(0, self._xoffset))
self._yoffset = min(raw_height - zoom_height, max(0, self._yoffset))
def get_current_view(self) -> pygame.Surface:
""" Get the subimage to display to screen from the map.
"""
raw_width = self.image.get_width()
raw_height = self.image.get_height()
zoom_width = round(raw_width / self._zoom)
zoom_height = round(raw_height / self._zoom)
mapsegment = self.image.subsurface(((self._xoffset, self._yoffset),
(zoom_width, zoom_height)))
return pygame.transform.smoothscale(mapsegment, self.screensize)
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={
'allowed-import-modules': [
'doctest', 'python_ta', 'typing',
'tkinter', 'os', 'pygame',
'threading', 'math', 'time',
'customer', 'call', 'filter',
],
'allowed-io': [
'entry_window', 'callback_wrapper', 'threading_wrapper',
'__init__', 'handle_window_events'
],
'disable': ['R0915', 'W0613', 'W0401', 'R0201'],
'generated-members': 'pygame.*'
})
__MACOSX/starter_code-2/._visualizer.py
starter_code-2/dataset.json
{"events": [{"type": "sms", "src_number": "776-2120", "dst_number": "839-0275", "time": "2018-01-01 09:44:14", "src_loc": [-79.67406228655243, 43.70727892550828], "dst_loc": [-79.30498277210351, 43.64927878254314]}, {"type": "call", "src_number": "938-6680", "dst_number": "674-6199", "time": "2018-01-01 11:05:55", "duration": 305, "src_loc": [-79.49877597785999, 43.60212042242521], "dst_loc": [-79.44914130508965, 43.758957913726896]}, {"type": "sms", "src_number": "247-2510", "dst_number": "698-0146", "time": "2018-01-01 13:56:34", "src_loc": [-79.63088166540733, 43.62982612424343], "dst_loc": [-79.3145961533051, 43.7555356005157]}, {"type": "sms", "src_number": "165-7838", "dst_number": "628-1219", "time": "2018-01-01 20:10:56", "src_loc": [-79.41712961780111, 43.69775878465157], "dst_loc": [-79.52022463020653, 43.667528298933334]}, {"type": "call", "src_number": "056-7577", "dst_number": "285-3740", "time": "2018-01-02 02:03:15", "duration": 163, "src_loc": [-79.24422244488586, 43.77413520361959], "dst_loc": [-79.33181640187328, 43.75083004709019]}, {"type": "sms", "src_number": "334-0547", "dst_number": "611-2902", "time": "2018-01-02 03:03:53", "src_loc": [-79.41414510099095, 43.63591498100487], "dst_loc": [-79.43253057464823, 43.73169178852711]}, {"type": "call", "src_number": "496-5543", "dst_number": "871-6653", "time": "2018-01-02 07:56:20", "duration": 321, "src_loc": [-79.69342977888867, 43.57804035120256], "dst_loc": [-79.26141442215547, 43.70123217109055]}, {"type": "call", "src_number": "050-0105", "dst_number": "696-2653", "time": "2018-01-02 12:32:46", "duration": 133, "src_loc": [-79.54436752829307, 43.73929365615721], "dst_loc": [-79.44050232585877, 43.66062108305516]}, {"type": "call", "src_number": "832-2301", "dst_number": "824-8496", "time": "2018-01-02 14:41:07", "duration": 324, "src_loc": [-79.60802878991359, 43.693351585074346], "dst_loc": [-79.35293268943096, 43.79505647636809]}, {"type": "sms", "src_number": "913-2332", "dst_number": "730-7684", "time": "2018-01-02 16:42:53", "src_loc": [-79.46541959701995, 43.7606014175198], "dst_loc": [-79.5389825061505, 43.62726017734569]}, {"type": "sms", "src_number": "843-6834", "dst_number": "993-4723", "time": "2018-01-02 23:20:06", "src_loc": [-79.67355734784488, 43.600399301141934], "dst_loc": [-79.57812839679308, 43.60258260418795]}, {"type": "call", "src_number": "824-8496", "dst_number": "835-1248", "time": "2018-01-03 00:46:34", "duration": 196, "src_loc": [-79.38870227128515, 43.75778630255226], "dst_loc": [-79.20266410303202, 43.65216911152068]}, {"type": "sms", "src_number": "277-0239", "dst_number": "373-3350", "time": "2018-01-03 02:33:25", "src_loc": [-79.3181487698864, 43.71893579760639], "dst_loc": [-79.63202262701112, 43.797600288753074]}, {"type": "sms", "src_number": "575-6924", "dst_number": "533-1214", "time": "2018-01-03 04:06:00", "src_loc": [-79.35931926326565, 43.739308356397046], "dst_loc": [-79.46866717947026, 43.74273886378449]}, {"type": "sms", "src_number": "649-0500", "dst_number": "006-3878", "time": "2018-01-03 06:01:55", "src_loc": [-79.3282737094879, 43.68513147513064], "dst_loc": [-79.6815448350069, 43.63645839756315]}, {"type": "sms", "src_number": "059-4057", "dst_number": "102-9506", "time": "2018-01-03 07:29:54", "src_loc": [-79.56713264587303, 43.73831227476857], "dst_loc": [-79.39055307175315, 43.633440454325]}, {"type": "call", "src_number": "100-8771", "dst_number": "463-0109", "time": "2018-01-03 09:30:28", "duration": 322, "src_loc": [-79.64766801685782, 43.63849731441832], "dst_loc": [-79.4033654340801, 43.64676624965331]}, {"type": "sms", "src_number": "987-2747", "dst_number": "241-0963", "time": "2018-01-03 12:32:04", "src_loc": [-79.27688286733527, 43.678029880470824], "dst_loc": [-79.6025473101743, 43.770289240259125]}, {"type": "call", "src_number": "862-3646", "dst_number": "628-1219", "time": "2018-01-03 16:22:33", "duration": 270, "src_loc": [-79.2019388259489, 43.730170367672045], "dst_loc": [-79.62013525898622, 43.705310955370436]}, {"type": "call", "src_number": "006-3878", "dst_number": "696-2653", "time": "2018-01-03 18:12:19", "duration": 284, "src_loc": [-79.53197307243349, 43.634042426127294], "dst_loc": [-79.63208934720531, 43.58749975924126]}, {"type": "call", "src_number": "300-7295", "dst_number": "730-5600", "time": "2018-01-04 00:04:27", "duration": 81, "src_loc": [-79.4537984572693, 43.691041754578535], "dst_loc": [-79.33435457922519, 43.707046709462276]}, {"type": "call", "src_number": "938-6680", "dst_number": "730-5600", "time": "2018-01-04 14:58:07", "duration": 301, "src_loc": [-79.54717029563304, 43.58020061333404], "dst_loc": [-79.31511855020865, 43.61495646767958]}, {"type": "call", "src_number": "824-8496", "dst_number": "373-3350", "time": "2018-01-04 17:00:00", "duration": 203, "src_loc": [-79.26403584840118, 43.658578064986294], "dst_loc": [-79.27768087021423, 43.68802302935565]}, {"type": "sms", "src_number": "668-3514", "dst_number": "142-5525", "time": "2018-01-05 03:13:57", "src_loc": [-79.53282687724422, 43.67389313968766], "dst_loc": [-79.37451392155718, 43.61493258584348]}, {"type": "call", "src_number": "936-4231", "dst_number": "839-6337", "time": "2018-01-05 04:48:00", "duration": 91, "src_loc": [-79.2079781340112, 43.65767041901683], "dst_loc": [-79.51119008281646, 43.666849635058625]}, {"type": "call", "src_number": "129-8541", "dst_number": "990-0629", "time": "2018-01-05 07:04:06", "duration": 264, "src_loc": [-79.49230222546187, 43.7598826258876], "dst_loc": [-79.55777861385711, 43.66121709273177]}, {"type": "sms", "src_number": "940-6196", "dst_number": "592-4066", "time": "2018-01-05 08:00:35", "src_loc": [-79.25392315218693, 43.693331621099155], "dst_loc": [-79.47674995597465, 43.73962032872]}, {"type": "call", "src_number": "533-1214", "dst_number": "731-6163", "time": "2018-01-05 12:29:15", "duration": 61, "src_loc": [-79.54909954357234, 43.655887932477825], "dst_loc": [-79.2743070643613, 43.6402452783943]}, {"type": "sms", "src_number": "520-2727", "dst_number": "637-0682", "time": "2018-01-05 14:41:32", "src_loc": [-79.57158819958472, 43.693715588084515], "dst_loc": [-79.68457846725991, 43.67640335129593]}, {"type": "sms", "src_number": "862-3646", "dst_number": "401-3187", "time": "2018-01-06 00:42:27", "src_loc": [-79.38892969466735, 43.73580596531158], "dst_loc": [-79.66346829510047, 43.643430470205665]}, {"type": "call", "src_number": "597-9070", "dst_number": "956-4003", "time": "2018-01-06 01:02:47", "duration": 182, "src_loc": [-79.60104741898402, 43.73060458103853], "dst_loc": [-79.2841268202547, 43.71350412475424]}, {"type": "call", "src_number": "006-3878", "dst_number": "418-9185", "time": "2018-01-06 01:15:01", "duration": 38, "src_loc": [-79.40770521600528, 43.60467018173296], "dst_loc": [-79.41510421157959, 43.578944502397114]}, {"type": "sms", "src_number": "708-6848", "dst_number": "198-0536", "time": "2018-01-06 08:46:52", "src_loc": [-79.25963186530988, 43.72758907038445], "dst_loc": [-79.41500642216496, 43.73491414012541]}, {"type": "sms", "src_number": "293-2025", "dst_number": "444-0066", "time": "2018-01-06 16:22:27", "src_loc": [-79.35954688608511, 43.62749381216327], "dst_loc": [-79.27471945814955, 43.67530407666513]}, {"type": "sms", "src_number": "161-4158", "dst_number": "430-4508", "time": "2018-01-06 17:17:03", "src_loc": [-79.58251144846474, 43.623510097350334], "dst_loc": [-79.37271957679349, 43.64182998071287]}, {"type": "sms", "src_number": "112-9752", "dst_number": "003-3751", "time": "2018-01-06 18:01:58", "src_loc": [-79.51594858829141, 43.74806303482998], "dst_loc": [-79.5902220744822, 43.5831899926382]}, {"type": "sms", "src_number": "444-0066", "dst_number": "412-2420", "time": "2018-01-06 19:17:09", "src_loc": [-79.22921675401936, 43.62355414852692], "dst_loc": [-79.21983513415361, 43.60396140453009]}, {"type": "call", "src_number": "300-7295", "dst_number": "784-0925", "time": "2018-01-07 01:38:47", "duration": 109, "src_loc": [-79.24245969002672, 43.624241859334795], "dst_loc": [-79.32254158434391, 43.612534143365274]}, {"type": "sms", "src_number": "607-9319", "dst_number": "936-4231", "time": "2018-01-07 01:45:21", "src_loc": [-79.42454324147307, 43.656164866486684], "dst_loc": [-79.64913030521377, 43.63072126621635]}, {"type": "sms", "src_number": "099-1900", "dst_number": "444-0066", "time": "2018-01-07 03:45:24", "src_loc": [-79.69252497456388, 43.65748220493364], "dst_loc": [-79.29509830086768, 43.597999423618695]}, {"type": "sms", "src_number": "346-8644", "dst_number": "129-8541", "time": "2018-01-07 06:06:02", "src_loc": [-79.62796709816153, 43.68094046877313], "dst_loc": [-79.20513377270564, 43.79653299161143]}, {"type": "call", "src_number": "731-6514", "dst_number": "581-0237", "time": "2018-01-07 07:34:22", "duration": 18, "src_loc": [-79.52261420222837, 43.65700815276033], "dst_loc": [-79.38316975122211, 43.680925245805994]}, {"type": "sms", "src_number": "654-6297", "dst_number": "463-0109", "time": "2018-01-07 08:18:02", "src_loc": [-79.51126244706258, 43.578066714158744], "dst_loc": [-79.63306608596459, 43.7550766914385]}, {"type": "call", "src_number": "987-2747", "dst_number": "820-8986", "time": "2018-01-07 11:32:26", "duration": 14, "src_loc": [-79.21105133798072, 43.58582395068167], "dst_loc": [-79.30821272364325, 43.6916616599624]}, {"type": "sms", "src_number": "459-5273", "dst_number": "971-4536", "time": "2018-01-07 12:26:44", "src_loc": [-79.29733598792862, 43.57865371478416], "dst_loc": [-79.46761132863476, 43.69377783985488]}, {"type": "call", "src_number": "592-4066", "dst_number": "871-6653", "time": "2018-01-07 14:46:45", "duration": 248, "src_loc": [-79.50007316628995, 43.58161586716922], "dst_loc": [-79.49591258461501, 43.69964953140681]}, {"type": "sms", "src_number": "048-4695", "dst_number": "839-0038", "time": "2018-01-07 21:13:34", "src_loc": [-79.51378529280056, 43.67456962575426], "dst_loc": [-79.59232021902177, 43.6991330136348]}, {"type": "call", "src_number": "493-8650", "dst_number": "871-6653", "time": "2018-01-08 01:32:53", "duration": 332, "src_loc": [-79.20366626407794, 43.66536478057691], "dst_loc": [-79.26724152151735, 43.644154349331636]}, {"type": "sms", "src_number": "665-2075", "dst_number": "373-3350", "time": "2018-01-08 02:07:01", "src_loc": [-79.63637744679589, 43.742984196738135], "dst_loc": [-79.3159948243952, 43.69808380847264]}, {"type": "call", "src_number": "010-3671", "dst_number": "003-3751", "time": "2018-01-08 13:50:47", "duration": 228, "src_loc": [-79.65427688179467, 43.57970398268384], "dst_loc": [-79.52734620498566, 43.755670347103724]}, {"type": "sms", "src_number": "839-7840", "dst_number": "459-5273", "time": "2018-01-08 20:08:40", "src_loc": [-79.25043267097325, 43.68505870056715], "dst_loc": [-79.5986005641333, 43.70960647387574]}, {"type": "sms", "src_number": "328-2096", "dst_number": "444-0066", "time": "2018-01-08 20:32:20", "src_loc": [-79.37755825294823, 43.765960425597], "dst_loc": [-79.31760574502015, 43.6865498795319]}, {"type": "sms", "src_number": "285-3740", "dst_number": "998-1883", "time": "2018-01-08 21:31:40", "src_loc": [-79.48779210073988, 43.68643052724031], "dst_loc": [-79.4990521076639, 43.649126738766235]}, {"type": "sms", "src_number": "059-4057", "dst_number": "247-2510", "time": "2018-01-09 04:13:09", "src_loc": [-79.44057879170818, 43.600037365767896], "dst_loc": [-79.30513308139848, 43.577887836132135]}, {"type": "call", "src_number": "871-6653", "dst_number": "412-2420", "time": "2018-01-09 06:57:57", "duration": 154, "src_loc": [-79.62724786220454, 43.70453558610335], "dst_loc": [-79.39350202921781, 43.71646296027874]}, {"type": "sms", "src_number": "370-6462", "dst_number": "971-4536", "time": "2018-01-09 10:03:44", "src_loc": [-79.55707164720829, 43.663608302052864], "dst_loc": [-79.29352473000124, 43.68970508957421]}, {"type": "sms", "src_number": "731-6163", "dst_number": "839-7840", "time": "2018-01-09 12:16:23", "src_loc": [-79.60427630727446, 43.646057597055005], "dst_loc": [-79.6076341842898, 43.70426850147826]}, {"type": "call", "src_number": "698-0146", "dst_number": "380-5011", "time": "2018-01-09 15:28:38", "duration": 272, "src_loc": [-79.37075747653459, 43.78722242542597], "dst_loc": [-79.4049659085542, 43.598093728867816]}, {"type": "call", "src_number": "183-7942", "dst_number": "668-3514", "time": "2018-01-09 15:52:19", "duration": 89, "src_loc": [-79.37551083202906, 43.67031392343567], "dst_loc": [-79.67687278459942, 43.62175915693354]}, {"type": "sms", "src_number": "914-9837", "dst_number": "013-3456", "time": "2018-01-09 17:48:49", "src_loc": [-79.37969442159617, 43.714408997628546], "dst_loc": [-79.52981031587542, 43.604439071034996]}, {"type": "call", "src_number": "380-5011", "dst_number": "961-1759", "time": "2018-01-09 18:05:30", "duration": 288, "src_loc": [-79.52793641616302, 43.697734691366726], "dst_loc": [-79.68402823093548, 43.726466393302374]}, {"type": "sms", "src_number": "832-2301", "dst_number": "142-5525", "time": "2018-01-09 18:49:19", "src_loc": [-79.61227444370269, 43.69280548896062], "dst_loc": [-79.3424980486224, 43.79691389139773]}, {"type": "sms", "src_number": "730-5600", "dst_number": "178-3378", "time": "2018-01-09 22:12:36", "src_loc": [-79.37565439771913, 43.763503198552], "dst_loc": [-79.54883514551562, 43.647158263085565]}, {"type": "sms", "src_number": "649-0500", "dst_number": "628-9627", "time": "2018-01-10 02:47:34", "src_loc": [-79.51600932571661, 43.65717441472133], "dst_loc": [-79.4694826645782, 43.65960012473842]}, {"type": "call", "src_number": "059-4057", "dst_number": "987-2747", "time": "2018-01-10 07:12:38", "duration": 40, "src_loc": [-79.36857336678734, 43.73480181057429], "dst_loc": [-79.60595661356118, 43.65961376277408]}, {"type": "call", "src_number": "676-5324", "dst_number": "831-3310", "time": "2018-01-10 17:01:26", "duration": 119, "src_loc": [-79.34562443941661, 43.774545620665045], "dst_loc": [-79.58286717813802, 43.78636190888336]}, {"type": "call", "src_number": "961-1759", "dst_number": "129-8541", "time": "2018-01-10 19:22:57", "duration": 129, "src_loc": [-79.37699057963226, 43.77694267438579], "dst_loc": [-79.24968025585535, 43.69845982010377]}, {"type": "sms", "src_number": "806-5506", "dst_number": "261-2835", "time": "2018-01-10 20:43:08", "src_loc": [-79.54064011866342, 43.63965266673999], "dst_loc": [-79.60047757431803, 43.72603768110868]}, {"type": "sms", "src_number": "644-8064", "dst_number": "835-1248", "time": "2018-01-10 21:46:30", "src_loc": [-79.62739253901992, 43.67336570021128], "dst_loc": [-79.5501391426594, 43.72706431004959]}, {"type": "call", "src_number": "961-1759", "dst_number": "932-2436", "time": "2018-01-11 00:28:19", "duration": 255, "src_loc": [-79.40329718847185, 43.61360933656805], "dst_loc": [-79.40426860556673, 43.70035519428543]}, {"type": "sms", "src_number": "198-0536", "dst_number": "784-0925", "time": "2018-01-11 02:21:47", "src_loc": [-79.26276830576765, 43.62819967483527], "dst_loc": [-79.5402673278375, 43.64368671247442]}, {"type": "call", "src_number": "006-3878", "dst_number": "430-4508", "time": "2018-01-11 02:35:23", "duration": 300, "src_loc": [-79.50570739400892, 43.69513525962271], "dst_loc": [-79.6957955807145, 43.73255472981517]}, {"type": "call", "src_number": "101-7414", "dst_number": "293-2025", "time": "2018-01-11 03:57:20", "duration": 196, "src_loc": [-79.5237417064168, 43.773790522197146], "dst_loc": [-79.52987163327002, 43.713236221446635]}, {"type": "call", "src_number": "845-3937", "dst_number": "603-0289", "time": "2018-01-11 05:11:41", "duration": 322, "src_loc": [-79.6042875786048, 43.794908835897786], "dst_loc": [-79.36796784921367, 43.79540845321941]}, {"type": "call", "src_number": "286-6787", "dst_number": "730-5600", "time": "2018-01-11 10:26:41", "duration": 96, "src_loc": [-79.67387618582906, 43.66802106708983], "dst_loc": [-79.5732118275938, 43.59958686353122]}, {"type": "sms", "src_number": "681-8883", "dst_number": "542-8018", "time": "2018-01-11 14:51:10", "src_loc": [-79.59075622772212, 43.63010785722206], "dst_loc": [-79.4545396570001, 43.655960370329524]}, {"type": "sms", "src_number": "542-8018", "dst_number": "444-0066", "time": "2018-01-11 18:21:59", "src_loc": [-79.40885229812663, 43.792531327178736], "dst_loc": [-79.48527777237571, 43.59605169737585]}, {"type": "call", "src_number": "611-2902", "dst_number": "580-3656", "time": "2018-01-11 20:29:08", "duration": 350, "src_loc": [-79.30573062564999, 43.59390038939616], "dst_loc": [-79.62982088743715, 43.795027485627]}, {"type": "call", "src_number": "695-4637", "dst_number": "126-2700", "time": "2018-01-11 22:24:28", "duration": 213, "src_loc": [-79.54108499598492, 43.69469635180983], "dst_loc": [-79.45806319837901, 43.61028937295674]}, {"type": "call", "src_number": "112-9752", "dst_number": "329-4692", "time": "2018-01-12 00:19:15", "duration": 47, "src_loc": [-79.6822302384206, 43.57806716581824], "dst_loc": [-79.44095721158409, 43.73520426126865]}, {"type": "sms", "src_number": "617-3262", "dst_number": "820-8986", "time": "2018-01-12 00:52:19", "src_loc": [-79.52237801982035, 43.68181178337716], "dst_loc": [-79.51952960594825, 43.77240269203005]}, {"type": "sms", "src_number": "832-2301", "dst_number": "010-3671", "time": "2018-01-12 01:06:00", "src_loc": [-79.60545036217661, 43.643797117284905], "dst_loc": [-79.58936690704283, 43.66334254160876]}, {"type": "sms", "src_number": "142-5525", "dst_number": "956-4003", "time": "2018-01-12 05:33:42", "src_loc": [-79.47022895101352, 43.68843384296585], "dst_loc": [-79.27007827374386, 43.74541285988904]}, {"type": "sms", "src_number": "338-1977", "dst_number": "497-8688", "time": "2018-01-12 11:12:15", "src_loc": [-79.32110153277249, 43.66574246932072], "dst_loc": [-79.54908053532826, 43.66711804596395]}, {"type": "call", "src_number": "947-1649", "dst_number": "617-3262", "time": "2018-01-12 12:34:04", "duration": 17, "src_loc": [-79.23725224853939, 43.59276512017153], "dst_loc": [-79.26719791410392, 43.722073437287776]}, {"type": "sms", "src_number": "047-5142", "dst_number": "009-8583", "time": "2018-01-12 14:20:33", "src_loc": [-79.58094942373967, 43.66699149561858], "dst_loc": [-79.5734873684463, 43.75786532167284]}, {"type": "call", "src_number": "300-7295", "dst_number": "575-6924", "time": "2018-01-13 01:08:08", "duration": 334, "src_loc": [-79.59168885583071, 43.733144198544075], "dst_loc": [-79.58806259186143, 43.75706334224579]}, {"type": "call", "src_number": "649-0500", "dst_number": "180-2368", "time": "2018-01-13 02:09:01", "duration": 263, "src_loc": [-79.26013513625395, 43.617553505502414], "dst_loc": [-79.41540905785176, 43.759040609061095]}, {"type": "call", "src_number": "971-4536", "dst_number": "936-4231", "time": "2018-01-13 03:02:57", "duration": 200, "src_loc": [-79.26851816661724, 43.60610611231158], "dst_loc": [-79.69092799600601, 43.73696567199281]}, {"type": "sms", "src_number": "542-8018", "dst_number": "006-3878", "time": "2018-01-13 07:02:20", "src_loc": [-79.54627294614588, 43.699018750414346], "dst_loc": [-79.47010997781422, 43.671233279610234]}, {"type": "call", "src_number": "413-0551", "dst_number": "637-0682", "time": "2018-01-13 08:30:20", "duration": 283, "src_loc": [-79.33852331254006, 43.61379305529684], "dst_loc": [-79.30690435736234, 43.585075707243206]}, {"type": "sms", "src_number": "537-6361", "dst_number": "407-3414", "time": "2018-01-13 08:33:59", "src_loc": [-79.34794843131971, 43.68615839957169], "dst_loc": [-79.31706064916634, 43.69922281121394]}, {"type": "call", "src_number": "784-0925", "dst_number": "412-2420", "time": "2018-01-13 12:54:34", "duration": 190, "src_loc": [-79.63184751621428, 43.69838974089598], "dst_loc": [-79.25135799796573, 43.71582998918007]}, {"type": "sms", "src_number": "542-8018", "dst_number": "784-0925", "time": "2018-01-13 14:39:33", "src_loc": [-79.3001838056724, 43.78184759605976], "dst_loc": [-79.3058740512167, 43.724055171596035]}, {"type": "call", "src_number": "277-0239", "dst_number": "413-0551", "time": "2018-01-13 18:51:21", "duration": 245, "src_loc": [-79.62014708033429, 43.68900200701229], "dst_loc": [-79.5761252838882, 43.787104535193855]}, {"type": "call", "src_number": "101-7414", "dst_number": "119-8468", "time": "2018-01-13 19:53:43", "duration": 79, "src_loc": [-79.42783105388449, 43.58392145820992], "dst_loc": [-79.43672458438752, 43.79477088820857]}, {"type": "call", "src_number": "730-5600", "dst_number": "137-5770", "time": "2018-01-13 21:00:25", "duration": 190, "src_loc": [-79.23022287306664, 43.752718747925314], "dst_loc": [-79.49598567590151, 43.58134030116757]}, {"type": "call", "src_number": "661-9241", "dst_number": "137-0722", "time": "2018-01-14 01:01:58", "duration": 36, "src_loc": [-79.22275477301001, 43.58878211375385], "dst_loc": [-79.40446032217965, 43.61274531378145]}, {"type": "call", "src_number": "165-7838", "dst_number": "482-2360", "time": "2018-01-14 01:11:04", "duration": 314, "src_loc": [-79.59710261937656, 43.70399012549619], "dst_loc": [-79.43485522850881, 43.79528830317918]}, {"type": "sms", "src_number": "493-8650", "dst_number": "784-0925", "time": "2018-01-14 10:29:20", "src_loc": [-79.53730433892723, 43.61614830645385], "dst_loc": [-79.2578531165587, 43.599751259231894]}, {"type": "sms", "src_number": "493-8650", "dst_number": "603-0289", "time": "2018-01-14 12:25:13", "src_loc": [-79.47478704177375, 43.76534642729039], "dst_loc": [-79.37228669267405, 43.59719072320908]}, {"type": "sms", "src_number": "801-9566", "dst_number": "286-6787", "time": "2018-01-14 14:10:48", "src_loc": [-79.54025477621796, 43.73504053102937], "dst_loc": [-79.3948410633355, 43.57928486946592]}, {"type": "sms", "src_number": "010-3671", "dst_number": "654-6297", "time": "2018-01-14 20:41:24", "src_loc": [-79.26634957095996, 43.6673833990915], "dst_loc": [-79.38727241150197, 43.765770480861214]}, {"type": "call", "src_number": "059-4057", "dst_number": "142-5525", "time": "2018-01-14 22:38:32", "duration": 311, "src_loc": [-79.65093107624631, 43.742354343872016], "dst_loc": [-79.52409090067196, 43.659690660221464]}, {"type": "call", "src_number": "843-6834", "dst_number": "576-9648", "time": "2018-01-15 02:00:44", "duration": 304, "src_loc": [-79.41860687371602, 43.726319641791555], "dst_loc": [-79.21348108399486, 43.609590629689805]}, {"type": "call", "src_number": "009-8583", "dst_number": "676-5324", "time": "2018-01-15 07:04:57", "duration": 335, "src_loc": [-79.50910557481441, 43.698810006013936], "dst_loc": [-79.58799242757146, 43.766298067512565]}, {"type": "sms", "src_number": "047-5142", "dst_number": "142-5525", "time": "2018-01-15 13:25:08", "src_loc": [-79.3289996774918, 43.735161486617834], "dst_loc": [-79.58742551471859, 43.794181490202995]}, {"type": "sms", "src_number": "286-6787", "dst_number": "119-8468", "time": "2018-01-15 14:27:35", "src_loc": [-79.28923167308983, 43.705773149140285], "dst_loc": [-79.45128378425497, 43.74262246431038]}, {"type": "call", "src_number": "849-3472", "dst_number": "401-3187", "time": "2018-01-15 19:26:33", "duration": 284, "src_loc": [-79.4826101670566, 43.7412367520351], "dst_loc": [-79.3202545626825, 43.77494722170838]}, {"type": "call", "src_number": "390-1713", "dst_number": "178-3378", "time": "2018-01-15 20:55:02", "duration": 180, "src_loc": [-79.35928604230101, 43.76099508684154], "dst_loc": [-79.33418362050143, 43.78644723802974]}, {"type": "call", "src_number": "801-9566", "dst_number": "730-7684", "time": "2018-01-15 22:33:56", "duration": 193, "src_loc": [-79.4727959464315, 43.6944882801766], "dst_loc": [-79.27329211166108, 43.68814488774526]}, {"type": "sms", "src_number": "696-4364", "dst_number": "744-6324", "time": "2018-01-16 02:40:21", "src_loc": [-79.23041633264242, 43.60907122027134], "dst_loc": [-79.43500460152787, 43.60874118667851]}, {"type": "call", "src_number": "580-3656", "dst_number": "990-0629", "time": "2018-01-16 02:48:28", "duration": 269, "src_loc": [-79.66565956856223, 43.608203662146174], "dst_loc": [-79.69637886600961, 43.614687433560746]}, {"type": "sms", "src_number": "644-8064", "dst_number": "560-7837", "time": "2018-01-16 08:35:06", "src_loc": [-79.53331811341755, 43.78325905715772], "dst_loc": [-79.64664072290546, 43.65634771421108]}, {"type": "sms", "src_number": "696-2653", "dst_number": "202-2830", "time": "2018-01-16 08:45:47", "src_loc": [-79.49070605903894, 43.68898797636147], "dst_loc": [-79.37524626937795, 43.78661849682256]}, {"type": "call", "src_number": "993-3441", "dst_number": "286-6787", "time": "2018-01-16 10:14:33", "duration": 248, "src_loc": [-79.24558750611436, 43.68905628506354], "dst_loc": [-79.51989562718796, 43.68505177064083]}, {"type": "sms", "src_number": "914-9837", "dst_number": "497-8688", "time": "2018-01-16 14:32:39", "src_loc": [-79.29098596410503, 43.67739481567266], "dst_loc": [-79.61131527948835, 43.69315058041223]}, {"type": "call", "src_number": "696-2653", "dst_number": "835-1248", "time": "2018-01-16 21:29:53", "duration": 220, "src_loc": [-79.27313388003954, 43.60438077438255], "dst_loc": [-79.23281137779779, 43.79673206013184]}, {"type": "call", "src_number": "277-0239", "dst_number": "849-3472", "time": "2018-01-16 22:19:38", "duration": 293, "src_loc": [-79.26515011489631, 43.78510909838326], "dst_loc": [-79.49487950951973, 43.65485367435405]}, {"type": "sms", "src_number": "137-0722", "dst_number": "006-3878", "time": "2018-01-16 22:39:24", "src_loc": [-79.37131360385959, 43.76687286644475], "dst_loc": [-79.50925410374074, 43.74051400895158]}, {"type": "sms", "src_number": "198-0536", "dst_number": "644-8064", "time": "2018-01-17 03:35:52", "src_loc": [-79.4853497238169, 43.741749475216835], "dst_loc": [-79.56999884477226, 43.60845801219503]}, {"type": "call", "src_number": "349-5337", "dst_number": "059-4057", "time": "2018-01-17 03:59:31", "duration": 250, "src_loc": [-79.4384913395394, 43.62102134374666], "dst_loc": [-79.39100653418305, 43.6398670600159]}, {"type": "call", "src_number": "603-0289", "dst_number": "329-4692", "time": "2018-01-17 04:04:43", "duration": 300, "src_loc": [-79.35254057558588, 43.758311561451585], "dst_loc": [-79.52989763763702, 43.696511356453776]}, {"type": "sms", "src_number": "607-9319", "dst_number": "815-0882", "time": "2018-01-17 07:34:45", "src_loc": [-79.47340316320667, 43.73141793137805], "dst_loc": [-79.50405630340731, 43.74144465367119]}, {"type": "sms", "src_number": "661-9241", "dst_number": "708-6848", "time": "2018-01-17 09:11:59", "src_loc": [-79.35528187654862, 43.72872359357342], "dst_loc": [-79.5371377810647, 43.67250941372903]}, {"type": "call", "src_number": "380-5011", "dst_number": "497-8688", "time": "2018-01-17 10:35:58", "duration": 321, "src_loc": [-79.55918204113351, 43.75892378493515], "dst_loc": [-79.3550537807653, 43.7524095791131]}, {"type": "call", "src_number": "971-4536", "dst_number": "731-6163", "time": "2018-01-17 12:06:55", "duration": 206, "src_loc": [-79.43411239505154, 43.75614318731803], "dst_loc": [-79.39487985681497, 43.72417025562037]}, {"type": "sms", "src_number": "629-6198", "dst_number": "649-0500", "time": "2018-01-17 15:00:45", "src_loc": [-79.37653588489238, 43.592538380304276], "dst_loc": [-79.66715055989128, 43.644437505781376]}, {"type": "call", "src_number": "334-0547", "dst_number": "681-8883", "time": "2018-01-17 19:57:54", "duration": 317, "src_loc": [-79.31815591565247, 43.7900184385362], "dst_loc": [-79.61046908792777, 43.69430284796392]}, {"type": "sms", "src_number": "947-1649", "dst_number": "993-4723", "time": "2018-01-17 21:03:31", "src_loc": [-79.40510011219709, 43.703730274607736], "dst_loc": [-79.61452113224658, 43.68968990271722]}, {"type": "call", "src_number": "101-7414", "dst_number": "731-6163", "time": "2018-01-18 06:33:45", "duration": 192, "src_loc": [-79.25035987428407, 43.783878712985455], "dst_loc": [-79.23097674862139, 43.61130495879614]}, {"type": "call", "src_number": "334-4295", "dst_number": "730-7684", "time": "2018-01-18 13:56:55", "duration": 249, "src_loc": [-79.43526915578126, 43.78054086590943], "dst_loc": [-79.23802419875206, 43.682403398300664]}, {"type": "call", "src_number": "592-4066", "dst_number": "261-2835", "time": "2018-01-18 15:14:03", "duration": 111, "src_loc": [-79.47187658708458, 43.684662024313866], "dst_loc": [-79.35290510679815, 43.59679843213539]}, {"type": "call", "src_number": "033-9988", "dst_number": "463-0109", "time": "2018-01-18 15:36:40", "duration": 187, "src_loc": [-79.43633588454476, 43.62400108942734], "dst_loc": [-79.58890427203471, 43.782319716595566]}, {"type": "sms", "src_number": "914-9837", "dst_number": "676-5324", "time": "2018-01-18 16:47:56", "src_loc": [-79.20707047452159, 43.70052466518845], "dst_loc": [-79.60253227518758, 43.69295452144067]}, {"type": "call", "src_number": "560-7837", "dst_number": "806-5506", "time": "2018-01-18 21:23:53", "duration": 143, "src_loc": [-79.4386263948658, 43.61388968666873], "dst_loc": [-79.56017290573554, 43.762188892148366]}, {"type": "call", "src_number": "346-8644", "dst_number": "009-8583", "time": "2018-01-18 22:08:03", "duration": 354, "src_loc": [-79.22661099584603, 43.628629192864956], "dst_loc": [-79.38817174413884, 43.712837046279446]}, {"type": "call", "src_number": "929-3363", "dst_number": "482-2360", "time": "2018-01-18 23:55:38", "duration": 90, "src_loc": [-79.65501642840135, 43.760633660957495], "dst_loc": [-79.63892322990388, 43.66404574606772]}, {"type": "call", "src_number": "644-8064", "dst_number": "159-1100", "time": "2018-01-19 05:40:17", "duration": 61, "src_loc": [-79.51944133147788, 43.60067681505971], "dst_loc": [-79.64288469835145, 43.58724739720348]}, {"type": "call", "src_number": "003-3751", "dst_number": "961-3055", "time": "2018-01-19 06:50:23", "duration": 218, "src_loc": [-79.57741542341567, 43.66439888968034], "dst_loc": [-79.38994237591073, 43.71080098517488]}, {"type": "sms", "src_number": "961-1759", "dst_number": "520-2727", "time": "2018-01-19 07:37:27", "src_loc": [-79.42000312897173, 43.65233976810541], "dst_loc": [-79.55895035101632, 43.593772027320036]}, {"type": "call", "src_number": "520-2727", "dst_number": "730-5600", "time": "2018-01-19 07:43:27", "duration": 65, "src_loc": [-79.28868112300222, 43.76826060895885], "dst_loc": [-79.64902961675654, 43.69802330590478]}, {"type": "call", "src_number": "668-3514", "dst_number": "102-9506", "time": "2018-01-19 08:00:26", "duration": 258, "src_loc": [-79.42906911359438, 43.66935735153906], "dst_loc": [-79.28336763563026, 43.66375323386153]}, {"type": "sms", "src_number": "099-1900", "dst_number": "533-1214", "time": "2018-01-19 08:42:42", "src_loc": [-79.53415434715518, 43.63312224424393], "dst_loc": [-79.4757702749552, 43.781540000295394]}, {"type": "call", "src_number": "349-5337", "dst_number": "099-1900", "time": "2018-01-19 09:37:27", "duration": 225, "src_loc": [-79.53490667723806, 43.63760429606875], "dst_loc": [-79.57324752613812, 43.7098345999575]}, {"type": "call", "src_number": "871-6653", "dst_number": "806-5506", "time": "2018-01-19 12:11:45", "duration": 156, "src_loc": [-79.59906242416758, 43.71543539174242], "dst_loc": [-79.65096568937967, 43.752101705634836]}, {"type": "call", "src_number": "938-6680", "dst_number": "430-4508", "time": "2018-01-19 14:51:32", "duration": 220, "src_loc": [-79.67621982395514, 43.707633517946036], "dst_loc": [-79.51866885116564, 43.702861005412906]}, {"type": "call", "src_number": "475-6203", "dst_number": "370-6462", "time": "2018-01-19 15:41:33", "duration": 259, "src_loc": [-79.58460373346657, 43.740385593213276], "dst_loc": [-79.5054393450373, 43.750448363296194]}, {"type": "call", "src_number": "047-5142", "dst_number": "277-0239", "time": "2018-01-19 15:52:30", "duration": 241, "src_loc": [-79.33596571946686, 43.61676146931326], "dst_loc": [-79.67450808784227, 43.75041590445127]}, {"type": "call", "src_number": "010-3671", "dst_number": "938-6680", "time": "2018-01-20 01:06:17", "duration": 348, "src_loc": [-79.3814038413827, 43.66098035684695], "dst_loc": [-79.60654159767151, 43.75978323027038]}, {"type": "sms", "src_number": "159-1100", "dst_number": "835-1248", "time": "2018-01-20 01:47:12", "src_loc": [-79.6123900837108, 43.598690145347135], "dst_loc": [-79.3079742573161, 43.79678829137365]}, {"type": "sms", "src_number": "580-3656", "dst_number": "129-8541", "time": "2018-01-20 03:58:17", "src_loc": [-79.32195651460633, 43.59897057086027], "dst_loc": [-79.65952112992085, 43.59589816491015]}, {"type": "sms", "src_number": "611-2902", "dst_number": "730-7684", "time": "2018-01-20 04:32:24", "src_loc": [-79.44811504277381, 43.642131403827925], "dst_loc": [-79.64174824086425, 43.72225532452896]}, {"type": "call", "src_number": "380-5011", "dst_number": "533-1214", "time": "2018-01-20 18:36:49", "duration": 29, "src_loc": [-79.39475192297076, 43.672078165512296], "dst_loc": [-79.39213970696615, 43.60049185466551]}, {"type": "sms", "src_number": "178-3378", "dst_number": "482-2360", "time": "2018-01-20 19:30:32", "src_loc": [-79.50431310479146, 43.60890857891749], "dst_loc": [-79.25501218022124, 43.7201844211002]}, {"type": "sms", "src_number": "286-6787", "dst_number": "698-0146", "time": "2018-01-20 22:03:48", "src_loc": [-79.388594479766, 43.63250266828986], "dst_loc": [-79.48467603872778, 43.73810914176037]}, {"type": "call", "src_number": "961-1759", "dst_number": "638-5474", "time": "2018-01-21 00:08:28", "duration": 222, "src_loc": [-79.42693903873784, 43.7457866145103], "dst_loc": [-79.6940153592882, 43.70432453350932]}, {"type": "sms", "src_number": "346-8644", "dst_number": "496-5543", "time": "2018-01-21 01:10:12", "src_loc": [-79.25934654082104, 43.59115342585325], "dst_loc": [-79.2488629921946, 43.620589347701454]}, {"type": "call", "src_number": "839-6337", "dst_number": "914-9837", "time": "2018-01-21 02:22:31", "duration": 33, "src_loc": [-79.25700024946882, 43.59059501635848], "dst_loc": [-79.39069934571391, 43.64917736033666]}, {"type": "call", "src_number": "603-0289", "dst_number": "698-0146", "time": "2018-01-21 03:40:39", "duration": 281, "src_loc": [-79.46991910175562, 43.693364717337495], "dst_loc": [-79.6871469523973, 43.598983504299134]}, {"type": "call", "src_number": "142-5525", "dst_number": "413-0551", "time": "2018-01-21 04:30:53", "duration": 313, "src_loc": [-79.60308774663169, 43.78719360797569], "dst_loc": [-79.67688937837454, 43.734706647168174]}, {"type": "sms", "src_number": "542-8018", "dst_number": "676-5324", "time": "2018-01-21 04:57:00", "src_loc": [-79.29754906855744, 43.792706635349674], "dst_loc": [-79.34735119504812, 43.5847522707497]}, {"type": "call", "src_number": "698-0146", "dst_number": "926-4806", "time": "2018-01-21 05:23:01", "duration": 96, "src_loc": [-79.50835593859703, 43.57736676538369], "dst_loc": [-79.63071091652361, 43.59869045766793]}, {"type": "sms", "src_number": "048-4695", "dst_number": "533-1214", "time": "2018-01-21 06:20:27", "src_loc": [-79.40676168631632, 43.796155464586526], "dst_loc": [-79.36764636564482, 43.76830707269861]}, {"type": "sms", "src_number": "430-4508", "dst_number": "657-3888", "time": "2018-01-21 06:43:49", "src_loc": [-79.36965642437345, 43.637185058172555], "dst_loc": [-79.52935290861897, 43.786095526813796]}, {"type": "call", "src_number": "137-0722", "dst_number": "560-7837", "time": "2018-01-21 14:57:52", "duration": 266, "src_loc": [-79.65299796177628, 43.59095958484395], "dst_loc": [-79.2603123364348, 43.79310313460459]}, {"type": "call", "src_number": "202-2830", "dst_number": "119-8468", "time": "2018-01-21 15:47:49", "duration": 48, "src_loc": [-79.4335426171567, 43.761029393603984], "dst_loc": [-79.2073948437806, 43.57842811858463]}, {"type": "sms", "src_number": "644-8064", "dst_number": "649-2182", "time": "2018-01-21 17:53:12", "src_loc": [-79.41129050490902, 43.69847657629391], "dst_loc": [-79.66501775785598, 43.62951472924933]}, {"type": "call", "src_number": "638-5474", "dst_number": "067-3729", "time": "2018-01-21 18:46:13", "duration": 258, "src_loc": [-79.69669915258494, 43.7597190374779], "dst_loc": [-79.49609774798303, 43.635729856841884]}, {"type": "call", "src_number": "575-6924", "dst_number": "987-2747", "time": "2018-01-21 21:23:26", "duration": 352, "src_loc": [-79.61348182001623, 43.6340185698654], "dst_loc": [-79.66083492007083, 43.73853867532899]}, {"type": "sms", "src_number": "496-5543", "dst_number": "649-2182", "time": "2018-01-21 23:22:52", "src_loc": [-79.24535597624653, 43.70730940670747], "dst_loc": [-79.47404813864765, 43.629323472775404]}, {"type": "sms", "src_number": "198-0536", "dst_number": "161-4158", "time": "2018-01-22 00:03:32", "src_loc": [-79.38429136626843, 43.60491269338669], "dst_loc": [-79.25981437198686, 43.75649575756238]}, {"type": "call", "src_number": "469-3515", "dst_number": "831-3310", "time": "2018-01-22 00:13:52", "duration": 4, "src_loc": [-79.6969883234294, 43.7296933535067], "dst_loc": [-79.20076881793452, 43.784787868341894]}, {"type": "sms", "src_number": "843-6834", "dst_number": "056-7577", "time": "2018-01-22 00:43:21", "src_loc": [-79.31631182326198, 43.79883302442272], "dst_loc": [-79.36075387996522, 43.61555619488839]}, {"type": "sms", "src_number": "047-5142", "dst_number": "698-0146", "time": "2018-01-22 02:47:47", "src_loc": [-79.31730440584559, 43.6349852596983], "dst_loc": [-79.34580184877977, 43.676622756779636]}, {"type": "sms", "src_number": "013-3456", "dst_number": "695-4637", "time": "2018-01-22 04:20:16", "src_loc": [-79.49383239649424, 43.704467027357715], "dst_loc": [-79.55475051186458, 43.72230508640807]}, {"type": "call", "src_number": "617-3262", "dst_number": "010-3671", "time": "2018-01-22 08:11:53", "duration": 52, "src_loc": [-79.31466365699735, 43.59187900584653], "dst_loc": [-79.28003690544602, 43.59081628862855]}, {"type": "call", "src_number": "731-6163", "dst_number": "048-4695", "time": "2018-01-22 12:49:38", "duration": 121, "src_loc": [-79.62887920949605, 43.79450383516973], "dst_loc": [-79.24884989502628, 43.78603959016892]}, {"type": "sms", "src_number": "839-0038", "dst_number": "560-7837", "time": "2018-01-22 15:25:37", "src_loc": [-79.33604579084809, 43.77835390189126], "dst_loc": [-79.62590349243288, 43.78143806988125]}, {"type": "sms", "src_number": "329-4692", "dst_number": "430-4508", "time": "2018-01-22 18:45:32", "src_loc": [-79.41084631688098, 43.767389840584215], "dst_loc": [-79.49209712261748, 43.66753689588675]}, {"type": "sms", "src_number": "137-0722", "dst_number": "832-2301", "time": "2018-01-22 18:56:55", "src_loc": [-79.20776708704688, 43.77214946693375], "dst_loc": [-79.34903155102431, 43.59471092325802]}, {"type": "call", "src_number": "839-7840", "dst_number": "580-3656", "time": "2018-01-22 21:48:19", "duration": 310, "src_loc": [-79.48825091452466, 43.724351808606805], "dst_loc": [-79.68557556850426, 43.58469287043672]}, {"type": "call", "src_number": "843-6834", "dst_number": "493-8650", "time": "2018-01-23 05:41:53", "duration": 312, "src_loc": [-79.67135544851801, 43.76621775571118], "dst_loc": [-79.26546399606366, 43.65617068258375]}, {"type": "sms", "src_number": "493-8650", "dst_number": "247-2510", "time": "2018-01-23 06:58:38", "src_loc": [-79.47216024351894, 43.58965147332041], "dst_loc": [-79.4998860513344, 43.69417855633002]}, {"type": "sms", "src_number": "029-7245", "dst_number": "161-4158", "time": "2018-01-23 08:27:37", "src_loc": [-79.49820553091122, 43.60623276466478], "dst_loc": [-79.43461865422536, 43.685839978257476]}, {"type": "sms", "src_number": "661-9241", "dst_number": "657-3888", "time": "2018-01-23 10:22:52", "src_loc": [-79.32232629097847, 43.79048525490957], "dst_loc": [-79.3616281230811, 43.62566608999743]}, {"type": "sms", "src_number": "776-2120", "dst_number": "277-0239", "time": "2018-01-23 11:09:15", "src_loc": [-79.30492750710071, 43.76256545010779], "dst_loc": [-79.44696268934048, 43.75542923263458]}, {"type": "call", "src_number": "059-4057", "dst_number": "942-5962", "time": "2018-01-23 12:06:47", "duration": 303, "src_loc": [-79.57456555766791, 43.59618168109082], "dst_loc": [-79.64539276795946, 43.681015804206965]}, {"type": "call", "src_number": "776-2120", "dst_number": "657-3888", "time": "2018-01-23 12:13:55", "duration": 99, "src_loc": [-79.42396404214395, 43.717849035161244], "dst_loc": [-79.21561924314845, 43.7343214482518]}, {"type": "sms", "src_number": "938-6680", "dst_number": "711-1347", "time": "2018-01-23 12:44:28", "src_loc": [-79.23971004603236, 43.7299780724881], "dst_loc": [-79.57153730223331, 43.60459838457176]}, {"type": "call", "src_number": "380-5011", "dst_number": "349-5337", "time": "2018-01-23 13:04:27", "duration": 91, "src_loc": [-79.51733915230444, 43.616608466757604], "dst_loc": [-79.21502820321126, 43.76109710510173]}, {"type": "call", "src_number": "940-6196", "dst_number": "776-2120", "time": "2018-01-23 23:52:52", "duration": 149, "src_loc": [-79.37206789322589, 43.642541987075084], "dst_loc": [-79.35228977266792, 43.77107036138659]}, {"type": "call", "src_number": "390-1713", "dst_number": "285-3740", "time": "2018-01-24 00:01:58", "duration": 53, "src_loc": [-79.44216931954546, 43.729776846073705], "dst_loc": [-79.38400475108219, 43.69523000703148]}, {"type": "sms", "src_number": "929-3363", "dst_number": "412-2420", "time": "2018-01-24 01:40:45", "src_loc": [-79.5755410800629, 43.76844313279314], "dst_loc": [-79.56244842916472, 43.62140423616982]}, {"type": "sms", "src_number": "286-6787", "dst_number": "843-6834", "time": "2018-01-24 04:19:11", "src_loc": [-79.52750762104286, 43.687780635517484], "dst_loc": [-79.6811231328201, 43.75965814481849]}, {"type": "call", "src_number": "942-5962", "dst_number": "129-8541", "time": "2018-01-24 07:05:36", "duration": 312, "src_loc": [-79.46400048486943, 43.74351338922679], "dst_loc": [-79.69584181230452, 43.6505534851455]}, {"type": "sms", "src_number": "784-0925", "dst_number": "961-1759", "time": "2018-01-24 09:38:42", "src_loc": [-79.37519909122376, 43.69014207623327], "dst_loc": [-79.21480617318502, 43.647475833773534]}, {"type": "call", "src_number": "418-9185", "dst_number": "824-8496", "time": "2018-01-24 20:49:18", "duration": 67, "src_loc": [-79.2548745723548, 43.77389072610522], "dst_loc": [-79.3673135089727, 43.6178250686217]}, {"type": "call", "src_number": "493-8650", "dst_number": "956-4003", "time": "2018-01-24 21:13:12", "duration": 200, "src_loc": [-79.44101869263697, 43.66852075252018], "dst_loc": [-79.29091934087043, 43.65623774688806]}, {"type": "call", "src_number": "459-5273", "dst_number": "095-6518", "time": "2018-01-24 21:16:45", "duration": 21, "src_loc": [-79.52577607049896, 43.79106341610474], "dst_loc": [-79.68148393651872, 43.590897048073884]}, {"type": "sms", "src_number": "708-6848", "dst_number": "580-3656", "time": "2018-01-25 09:57:53", "src_loc": [-79.38892898815868, 43.7593732516679], "dst_loc": [-79.20794718828536, 43.77646539328944]}, {"type": "call", "src_number": "059-4057", "dst_number": "776-2120", "time": "2018-01-25 10:59:52", "duration": 329, "src_loc": [-79.24745368790344, 43.740394582087774], "dst_loc": [-79.60364559056528, 43.64003539999735]}, {"type": "call", "src_number": "862-3646", "dst_number": "542-4197", "time": "2018-01-25 11:21:47", "duration": 251, "src_loc": [-79.29629777119764, 43.7268925653678], "dst_loc": [-79.48324834916122, 43.660938107792646]}, {"type": "sms", "src_number": "845-3937", "dst_number": "871-6653", "time": "2018-01-25 14:59:23", "src_loc": [-79.37232531420592, 43.71854080145652], "dst_loc": [-79.22604450610758, 43.75443656446287]}, {"type": "call", "src_number": "247-2510", "dst_number": "674-6199", "time": "2018-01-25 15:38:40", "duration": 118, "src_loc": [-79.35210605516903, 43.70112326222877], "dst_loc": [-79.37776858984323, 43.63604069833302]}, {"type": "sms", "src_number": "932-2436", "dst_number": "806-5506", "time": "2018-01-25 15:43:44", "src_loc": [-79.41907087064591, 43.59962385412002], "dst_loc": [-79.34737779991472, 43.65619984701492]}, {"type": "call", "src_number": "744-6324", "dst_number": "285-3740", "time": "2018-01-25 19:10:42", "duration": 40, "src_loc": [-79.20746148467572, 43.67831946011683], "dst_loc": [-79.39851182075648, 43.73861069570749]}, {"type": "sms", "src_number": "637-0682", "dst_number": "101-7414", "time": "2018-01-26 00:59:47", "src_loc": [-79.52172519136246, 43.77941197368062], "dst_loc": [-79.41158888712019, 43.73390780590735]}, {"type": "sms", "src_number": "202-2830", "dst_number": "444-0066", "time": "2018-01-26 04:54:27", "src_loc": [-79.60518664289192, 43.59213720725489], "dst_loc": [-79.48566700220451, 43.71432456739532]}, {"type": "sms", "src_number": "497-8688", "dst_number": "961-3055", "time": "2018-01-26 08:25:46", "src_loc": [-79.29012448008248, 43.689197100711105], "dst_loc": [-79.29463495049946, 43.74634955451005]}, {"type": "call", "src_number": "575-6924", "dst_number": "520-2727", "time": "2018-01-26 09:45:40", "duration": 78, "src_loc": [-79.63915265056835, 43.63322956282956], "dst_loc": [-79.36012838561187, 43.786348333516095]}, {"type": "call", "src_number": "346-8644", "dst_number": "839-6337", "time": "2018-01-26 10:25:00", "duration": 82, "src_loc": [-79.36154033840273, 43.730186650410175], "dst_loc": [-79.25800477155383, 43.74228087753397]}, {"type": "sms", "src_number": "285-3740", "dst_number": "241-0963", "time": "2018-01-26 18:38:44", "src_loc": [-79.23660140157315, 43.75439753712012], "dst_loc": [-79.21483702512712, 43.6966658081884]}, {"type": "call", "src_number": "629-6198", "dst_number": "913-2332", "time": "2018-01-26 23:03:43", "duration": 182, "src_loc": [-79.68105786894618, 43.68162888027694], "dst_loc": [-79.42180834712057, 43.71529935459478]}, {"type": "sms", "src_number": "824-8496", "dst_number": "592-4790", "time": "2018-01-27 00:15:48", "src_loc": [-79.69386882406415, 43.73124862125219], "dst_loc": [-79.56193826622946, 43.7470386492027]}, {"type": "sms", "src_number": "056-7577", "dst_number": "668-3514", "time": "2018-01-27 00:48:03", "src_loc": [-79.65070798625861, 43.59634170768844], "dst_loc": [-79.51844882126608, 43.760151355034544]}, {"type": "sms", "src_number": "202-2830", "dst_number": "293-2025", "time": "2018-01-27 00:52:30", "src_loc": [-79.44169337736069, 43.72118757117931], "dst_loc": [-79.6212961908827, 43.6480111199901]}, {"type": "call", "src_number": "329-4692", "dst_number": "947-1649", "time": "2018-01-27 02:26:15", "duration": 192, "src_loc": [-79.51286911820904, 43.72659884757036], "dst_loc": [-79.44342968240649, 43.60922856023945]}, {"type": "sms", "src_number": "497-8688", "dst_number": "029-7245", "time": "2018-01-27 19:06:54", "src_loc": [-79.31670862490998, 43.68514662262689], "dst_loc": [-79.23047075501862, 43.58885527890601]}, {"type": "call", "src_number": "839-0275", "dst_number": "649-2182", "time": "2018-01-28 01:19:03", "duration": 231, "src_loc": [-79.58276800519499, 43.602925525741824], "dst_loc": [-79.51843083465954, 43.70174159821493]}, {"type": "call", "src_number": "932-2436", "dst_number": "845-3937", "time": "2018-01-28 05:47:21", "duration": 212, "src_loc": [-79.318048694126, 43.74283094322586], "dst_loc": [-79.23001181052297, 43.64685518920275]}, {"type": "sms", "src_number": "862-3646", "dst_number": "629-5175", "time": "2018-01-28 08:19:54", "src_loc": [-79.28886518998995, 43.79349351017181], "dst_loc": [-79.5268844902694, 43.578521147973504]}, {"type": "call", "src_number": "380-5011", "dst_number": "285-3740", "time": "2018-01-28 09:03:02", "duration": 349, "src_loc": [-79.23136974144079, 43.69574811389531], "dst_loc": [-79.46247850951711, 43.795230994253664]}, {"type": "sms", "src_number": "285-3740", "dst_number": "971-4536", "time": "2018-01-28 11:39:03", "src_loc": [-79.64895145112543, 43.57896881478702], "dst_loc": [-79.5080645035465, 43.58210635436842]}, {"type": "call", "src_number": "390-1713", "dst_number": "695-4637", "time": "2018-01-28 17:19:57", "duration": 139, "src_loc": [-79.4232354067864, 43.6621759626488], "dst_loc": [-79.204746004463, 43.595897974870184]}, {"type": "sms", "src_number": "126-2700", "dst_number": "159-1100", "time": "2018-01-28 19:43:29", "src_loc": [-79.40721281788058, 43.76061275647351], "dst_loc": [-79.30972419537653, 43.63596240019874]}, {"type": "call", "src_number": "628-9627", "dst_number": "390-1713", "time": "2018-01-29 00:49:30", "duration": 5, "src_loc": [-79.56188152138881, 43.7757660338543], "dst_loc": [-79.25143670158559, 43.66100511194425]}, {"type": "call", "src_number": "871-6653", "dst_number": "832-2301", "time": "2018-01-29 03:30:44", "duration": 15, "src_loc": [-79.66105625118242, 43.610038440347466], "dst_loc": [-79.64449803183207, 43.583986914001045]}, {"type": "sms", "src_number": "009-8583", "dst_number": "099-1900", "time": "2018-01-29 05:27:56", "src_loc": [-79.44763796273352, 43.72409451608506], "dst_loc": [-79.21151295435632, 43.78418057220514]}, {"type": "call", "src_number": "285-3740", "dst_number": "731-6514", "time": "2018-01-29 12:00:06", "duration": 113, "src_loc": [-79.42015921471244, 43.742265841684244], "dst_loc": [-79.29915264328564, 43.647434385305544]}, {"type": "sms", "src_number": "067-3729", "dst_number": "676-5324", "time": "2018-01-30 01:45:27", "src_loc": [-79.48040070524188, 43.68476275104457], "dst_loc": [-79.38913423734387, 43.76211995151156]}, {"type": "call", "src_number": "482-2360", "dst_number": "832-2301", "time": "2018-01-30 02:16:44", "duration": 36, "src_loc": [-79.31926656175987, 43.778339151398264], "dst_loc": [-79.4910034862741, 43.68251941920273]}, {"type": "call", "src_number": "328-2096", "dst_number": "681-8883", "time": "2018-01-30 08:16:29", "duration": 43, "src_loc": [-79.63221492483403, 43.5861303851702], "dst_loc": [-79.44091670792623, 43.58397191634043]}, {"type": "sms", "src_number": "198-0536", "dst_number": "459-5273", "time": "2018-01-30 09:55:11", "src_loc": [-79.40489454260849, 43.60657385491975], "dst_loc": [-79.19640356834519, 43.63562651286339]}, {"type": "call", "src_number": "839-0275", "dst_number": "862-3646", "time": "2018-01-30 14:47:48", "duration": 95, "src_loc": [-79.5148500774525, 43.653098347822], "dst_loc": [-79.48599863925298, 43.69974524409387]}, {"type": "call", "src_number": "926-4806", "dst_number": "112-9752", "time": "2018-01-31 02:11:20", "duration": 228, "src_loc": [-79.60082273195718, 43.70537002067801], "dst_loc": [-79.28188185354212, 43.61822195913548]}, {"type": "sms", "src_number": "676-5324", "dst_number": "835-1248", "time": "2018-01-31 05:07:01", "src_loc": [-79.43532949709552, 43.645702431674], "dst_loc": [-79.43958533497397, 43.69420236597903]}, {"type": "call", "src_number": "560-7837", "dst_number": "126-2700", "time": "2018-01-31 09:08:03", "duration": 279, "src_loc": [-79.43815738977798, 43.596576925812265], "dst_loc": [-79.46369037050337, 43.71829966311802]}, {"type": "sms", "src_number": "334-0547", "dst_number": "661-9241", "time": "2018-01-31 11:26:37", "src_loc": [-79.27374406079602, 43.6592528077849], "dst_loc": [-79.59883662809256, 43.605039312853194]}, {"type": "call", "src_number": "126-2700", "dst_number": "676-5324", "time": "2018-01-31 11:56:17", "duration": 65, "src_loc": [-79.47695722644201, 43.74638031371519], "dst_loc": [-79.2928180653875, 43.711575570903065]}, {"type": "call", "src_number": "661-9241", "dst_number": "338-7780", "time": "2018-01-31 17:47:05", "duration": 94, "src_loc": [-79.42089064034344, 43.73671676345132], "dst_loc": [-79.53025381998772, 43.63582016584701]}, {"type": "call", "src_number": "126-2700", "dst_number": "346-8644", "time": "2018-01-31 18:35:15", "duration": 36, "src_loc": [-79.20728076581803, 43.68284307854063], "dst_loc": [-79.21236152179357, 43.77856150434104]}, {"type": "call", "src_number": "430-4508", "dst_number": "183-7942", "time": "2018-02-01 01:14:50", "duration": 206, "src_loc": [-79.44392973954831, 43.57913761585067], "dst_loc": [-79.65297110911233, 43.69636331988847]}, {"type": "call", "src_number": "129-8541", "dst_number": "059-4057", "time": "2018-02-01 03:47:12", "duration": 273, "src_loc": [-79.31294107443713, 43.770462079095225], "dst_loc": [-79.20641366417783, 43.727039117929564]}, {"type": "call", "src_number": "698-0146", "dst_number": "401-3187", "time": "2018-02-01 03:59:48", "duration": 188, "src_loc": [-79.53479752237013, 43.698192783077005], "dst_loc": [-79.32956005752676, 43.74415343922767]}, {"type": "call", "src_number": "926-4806", "dst_number": "159-1100", "time": "2018-02-01 08:54:01", "duration": 120, "src_loc": [-79.29602436929974, 43.76481069900668], "dst_loc": [-79.49823148701165, 43.77943498486238]}, {"type": "call", "src_number": "241-0963", "dst_number": "475-6203", "time": "2018-02-01 09:09:49", "duration": 159, "src_loc": [-79.63069880729697, 43.72739718512879], "dst_loc": [-79.58518244924932, 43.74383934359888]}, {"type": "call", "src_number": "009-8221", "dst_number": "831-3310", "time": "2018-02-01 14:16:17", "duration": 235, "src_loc": [-79.56263648608967, 43.66186172510967], "dst_loc": [-79.68131638427552, 43.76105366548707]}, {"type": "call", "src_number": "137-0722", "dst_number": "520-2727", "time": "2018-02-01 23:32:59", "duration": 80, "src_loc": [-79.27549498397805, 43.60261316055172], "dst_loc": [-79.36831953425661, 43.76753780441939]}, {"type": "call", "src_number": "418-9185", "dst_number": "993-3441", "time": "2018-02-02 02:23:50", "duration": 250, "src_loc": [-79.36550637781389, 43.63299305250695], "dst_loc": [-79.6815252114666, 43.74277135632668]}, {"type": "sms", "src_number": "059-4057", "dst_number": "661-9241", "time": "2018-02-02 10:31:54", "src_loc": [-79.48526776481562, 43.63948319613935], "dst_loc": [-79.58137362542784, 43.6460733538646]}, {"type": "sms", "src_number": "178-3378", "dst_number": "161-4158", "time": "2018-02-02 11:01:08", "src_loc": [-79.29049741567236, 43.69108334949572], "dst_loc": [-79.49483516097797, 43.726862538951295]}, {"type": "sms", "src_number": "439-9218", "dst_number": "373-3350", "time": "2018-02-02 11:36:10", "src_loc": [-79.61297481364608, 43.69270330071979], "dst_loc": [-79.66978159665403, 43.71393321434367]}, {"type": "sms", "src_number": "112-9752", "dst_number": "178-3378", "time": "2018-02-02 11:55:01", "src_loc": [-79.6403493192673, 43.79818858943891], "dst_loc": [-79.21339996584558, 43.610815391971244]}, {"type": "call", "src_number": "300-7295", "dst_number": "839-7840", "time": "2018-02-02 12:03:47", "duration": 114, "src_loc": [-79.42896610687262, 43.76635038565814], "dst_loc": [-79.46880980920375, 43.67294752286088]}, {"type": "sms", "src_number": "119-8468", "dst_number": "676-5324", "time": "2018-02-02 17:24:56", "src_loc": [-79.46855620651709, 43.750473492307805], "dst_loc": [-79.2800066737995, 43.665221689214846]}, {"type": "call", "src_number": "654-6297", "dst_number": "469-3515", "time": "2018-02-02 18:10:46", "duration": 180, "src_loc": [-79.5420562448553, 43.63646440262321], "dst_loc": [-79.38119880306236, 43.74449302190998]}, {"type": "sms", "src_number": "059-4057", "dst_number": "914-9837", "time": "2018-02-02 18:21:34", "src_loc": [-79.49262228540844, 43.79003248476327], "dst_loc": [-79.6349305284666, 43.74657232394516]}, {"type": "call", "src_number": "649-2182", "dst_number": "328-2096", "time": "2018-02-02 18:24:47", "duration": 153, "src_loc": [-79.59701899393654, 43.79530107283097], "dst_loc": [-79.1990666971706, 43.663011301027936]}, {"type": "call", "src_number": "722-8592", "dst_number": "938-6680", "time": "2018-02-02 21:13:20", "duration": 303, "src_loc": [-79.52012925837687, 43.729827279139336], "dst_loc": [-79.67051683847932, 43.70555104064998]}, {"type": "call", "src_number": "580-3656", "dst_number": "936-4231", "time": "2018-02-03 01:02:10", "duration": 35, "src_loc": [-79.59379549441951, 43.58613830562145], "dst_loc": [-79.34309252413294, 43.67807200257415]}, {"type": "call", "src_number": "731-6514", "dst_number": "654-6297", "time": "2018-02-03 01:48:12", "duration": 51, "src_loc": [-79.24152152060935, 43.77335817052213], "dst_loc": [-79.63393739487049, 43.674258586249614]}, {"type": "sms", "src_number": "180-2368", "dst_number": "629-6198", "time": "2018-02-03 03:58:14", "src_loc": [-79.40529440282693, 43.65534494933468], "dst_loc": [-79.68981104265262, 43.654247753461505]}, {"type": "sms", "src_number": "993-3441", "dst_number": "537-6361", "time": "2018-02-03 04:59:38", "src_loc": [-79.26476159865146, 43.67770205416232], "dst_loc": [-79.4883690435545, 43.7788497281896]}, {"type": "call", "src_number": "390-1713", "dst_number": "681-8883", "time": "2018-02-03 07:50:31", "duration": 288, "src_loc": [-79.53197513750808, 43.66163057836688], "dst_loc": [-79.29992855208141, 43.5864775979829]}, {"type": "sms", "src_number": "165-7838", "dst_number": "839-6337", "time": "2018-02-03 08:34:56", "src_loc": [-79.61962621532705, 43.67618593796325], "dst_loc": [-79.26348873835799, 43.76211644400444]}, {"type": "call", "src_number": "439-9218", "dst_number": "993-4723", "time": "2018-02-03 09:35:48", "duration": 275, "src_loc": [-79.51980993158973, 43.614679537802395], "dst_loc": [-79.28710301324402, 43.64250797350385]}, {"type": "sms", "src_number": "831-3310", "dst_number": "247-2510", "time": "2018-02-03 10:13:16", "src_loc": [-79.23947341907136, 43.73770328668601], "dst_loc": [-79.21419036955903, 43.64796866377672]}, {"type": "call", "src_number": "137-5770", "dst_number": "033-9988", "time": "2018-02-04 03:18:38", "duration": 281, "src_loc": [-79.30647843260255, 43.61849789426932], "dst_loc": [-79.62607490934717, 43.663433403991185]}, {"type": "sms", "src_number": "286-6787", "dst_number": "839-0275", "time": "2018-02-04 04:30:46", "src_loc": [-79.28924196383198, 43.60669049972329], "dst_loc": [-79.69109249147691, 43.603530123072915]}, {"type": "sms", "src_number": "614-5364", "dst_number": "839-0275", "time": "2018-02-04 06:55:14", "src_loc": [-79.54506673736475, 43.660675946685586], "dst_loc": [-79.4812498074273, 43.60855281322197]}, {"type": "sms", "src_number": "575-6924", "dst_number": "614-5364", "time": "2018-02-04 07:34:54", "src_loc": [-79.38071737982096, 43.6012020073388], "dst_loc": [-79.37704696676359, 43.75588513215892]}, {"type": "call", "src_number": "649-0500", "dst_number": "649-2182", "time": "2018-02-04 08:30:34", "duration": 293, "src_loc": [-79.56805617289272, 43.71831231702281], "dst_loc": [-79.32987589685374, 43.64933479390777]}, {"type": "sms", "src_number": "475-6203", "dst_number": "914-9837", "time": "2018-02-04 10:43:27", "src_loc": [-79.19922594004407, 43.73207147210225], "dst_loc": [-79.58763135230544, 43.669521446730826]}, {"type": "sms", "src_number": "059-4057", "dst_number": "731-6163", "time": "2018-02-04 10:48:32", "src_loc": [-79.5419472417652, 43.630488940704225], "dst_loc": [-79.42272665485181, 43.66569410889687]}, {"type": "sms", "src_number": "708-6848", "dst_number": "129-8541", "time": "2018-02-05 00:04:20", "src_loc": [-79.41329787303927, 43.5778491604278], "dst_loc": [-79.4817812971661, 43.68990081015766]}, {"type": "sms", "src_number": "493-8650", "dst_number": "102-9506", "time": "2018-02-05 02:35:49", "src_loc": [-79.32885769401491, 43.79029454474403], "dst_loc": [-79.34726680983579, 43.6373875463582]}, {"type": "sms", "src_number": "776-2120", "dst_number": "784-0925", "time": "2018-02-05 02:54:54", "src_loc": [-79.4005474049553, 43.704529280436155], "dst_loc": [-79.21874893664629, 43.65915058647817]}, {"type": "call", "src_number": "119-8468", "dst_number": "657-3888", "time": "2018-02-05 03:50:45", "duration": 99, "src_loc": [-79.19872279378284, 43.68705768634837], "dst_loc": [-79.53889046496305, 43.68117706401541]}, {"type": "sms", "src_number": "676-5324", "dst_number": "165-7838", "time": "2018-02-05 05:16:44", "src_loc": [-79.48785771202196, 43.74040911938776], "dst_loc": [-79.47903311651437, 43.70342428109974]}, {"type": "call", "src_number": "731-6163", "dst_number": "661-9241", "time": "2018-02-05 07:22:31", "duration": 181, "src_loc": [-79.31990458827934, 43.609135539851906], "dst_loc": [-79.42811344654699, 43.6942363341473]}, {"type": "call", "src_number": "119-8468", "dst_number": "956-4003", "time": "2018-02-05 08:17:03", "duration": 267, "src_loc": [-79.47471480703965, 43.605341837492006], "dst_loc": [-79.48994207209421, 43.59894460542449]}, {"type": "sms", "src_number": "820-8986", "dst_number": "277-0239", "time": "2018-02-05 14:27:39", "src_loc": [-79.26405877236944, 43.768000500044344], "dst_loc": [-79.53955902106232, 43.58529685015662]}, {"type": "call", "src_number": "674-6199", "dst_number": "100-8771", "time": "2018-02-05 18:49:35", "duration": 336, "src_loc": [-79.21558491106569, 43.641638169040704], "dst_loc": [-79.30400146423794, 43.605296042616374]}, {"type": "sms", "src_number": "137-5770", "dst_number": "183-7942", "time": "2018-02-05 19:52:25", "src_loc": [-79.61269592475422, 43.76723452470577], "dst_loc": [-79.36183835613542, 43.58996859385132]}, {"type": "sms", "src_number": "835-1248", "dst_number": "776-2120", "time": "2018-02-05 22:39:32", "src_loc": [-79.69705410430369, 43.72194950150018], "dst_loc": [-79.45295942170094, 43.7761273436893]}, {"type": "sms", "src_number": "607-9319", "dst_number": "463-0109", "time": "2018-02-06 01:38:11", "src_loc": [-79.35435955738576, 43.77285160563999], "dst_loc": [-79.46025665894794, 43.7627883963207]}, {"type": "call", "src_number": "801-9566", "dst_number": "475-6203", "time": "2018-02-06 03:29:19", "duration": 316, "src_loc": [-79.43394215289825, 43.721585643954775], "dst_loc": [-79.54817575140875, 43.58421620096383]}, {"type": "call", "src_number": "300-7295", "dst_number": "183-7942", "time": "2018-02-06 04:32:05", "duration": 58, "src_loc": [-79.3872903552524, 43.79109175346116], "dst_loc": [-79.62178983641677, 43.66551997613182]}, {"type": "sms", "src_number": "629-6198", "dst_number": "674-6199", "time": "2018-02-06 04:55:38", "src_loc": [-79.48254176706176, 43.63234722804406], "dst_loc": [-79.20509630342629, 43.789121214827986]}, {"type": "sms", "src_number": "843-6834", "dst_number": "560-7837", "time": "2018-02-06 10:13:34", "src_loc": [-79.25663004461899, 43.6452102511964], "dst_loc": [-79.52079809222538, 43.702719881430255]}, {"type": "call", "src_number": "346-8644", "dst_number": "832-2301", "time": "2018-02-06 16:24:11", "duration": 209, "src_loc": [-79.38595355229852, 43.69035590686048], "dst_loc": [-79.53842908647405, 43.657889855011994]}, {"type": "sms", "src_number": "198-0536", "dst_number": "731-6163", "time": "2018-02-07 00:52:49", "src_loc": [-79.50424001644481, 43.72732052102847], "dst_loc": [-79.45960379595459, 43.77349325668482]}, {"type": "sms", "src_number": "971-4536", "dst_number": "095-6518", "time": "2018-02-07 01:01:50", "src_loc": [-79.19695759776047, 43.6392601883764], "dst_loc": [-79.31450329252523, 43.70437197898618]}, {"type": "call", "src_number": "715-7430", "dst_number": "731-6163", "time": "2018-02-07 05:52:48", "duration": 338, "src_loc": [-79.22491525189224, 43.652177175018245], "dst_loc": [-79.46731390997299, 43.58828907916325]}, {"type": "call", "src_number": "668-3514", "dst_number": "277-0239", "time": "2018-02-07 15:11:16", "duration": 278, "src_loc": [-79.54751848600986, 43.77470361779713], "dst_loc": [-79.2214412083136, 43.70681519592702]}, {"type": "sms", "src_number": "334-4295", "dst_number": "095-6518", "time": "2018-02-07 18:55:12", "src_loc": [-79.65133659155721, 43.67019134599335], "dst_loc": [-79.2290765553155, 43.76952515730628]}, {"type": "call", "src_number": "839-0038", "dst_number": "617-3262", "time": "2018-02-07 20:09:58", "duration": 94, "src_loc": [-79.5277981640261, 43.6559564846429], "dst_loc": [-79.67207271585505, 43.609061025551426]}, {"type": "call", "src_number": "202-2830", "dst_number": "009-8221", "time": "2018-02-07 21:18:48", "duration": 74, "src_loc": [-79.64293440181073, 43.76437938575971], "dst_loc": [-79.3775855302057, 43.624117443096885]}, {"type": "call", "src_number": "824-8496", "dst_number": "843-6834", "time": "2018-02-07 21:28:29", "duration": 282, "src_loc": [-79.44000778759128, 43.61736005541944], "dst_loc": [-79.31796266055343, 43.79106289160258]}, {"type": "call", "src_number": "711-1347", "dst_number": "971-4536", "time": "2018-02-07 21:53:29", "duration": 28, "src_loc": [-79.49417965578935, 43.67519802210826], "dst_loc": [-79.32524003540486, 43.72523332046841]}, {"type": "sms", "src_number": "180-2368", "dst_number": "839-7840", "time": "2018-02-07 23:08:25", "src_loc": [-79.24795525136203, 43.605176347085894], "dst_loc": [-79.27573514999875, 43.669205447528974]}, {"type": "sms", "src_number": "401-3187", "dst_number": "119-8468", "time": "2018-02-07 23:27:19", "src_loc": [-79.31608742251538, 43.67129540102219], "dst_loc": [-79.26585544199592, 43.775875968576514]}, {"type": "sms", "src_number": "137-0722", "dst_number": "029-7245", "time": "2018-02-07 23:35:59", "src_loc": [-79.64319033734944, 43.635900293822516], "dst_loc": [-79.25649664064656, 43.694384324332134]}, {"type": "call", "src_number": "119-8468", "dst_number": "329-4692", "time": "2018-02-08 03:37:30", "duration": 14, "src_loc": [-79.4450240863912, 43.615143536358694], "dst_loc": [-79.62058645769753, 43.63400587879913]}, {"type": "call", "src_number": "839-0038", "dst_number": "722-8592", "time": "2018-02-08 06:05:30", "duration": 151, "src_loc": [-79.59249755450529, 43.763756747912986], "dst_loc": [-79.59121117358758, 43.78052486620574]}, {"type": "sms", "src_number": "542-4197", "dst_number": "056-7577", "time": "2018-02-08 07:00:13", "src_loc": [-79.59047111317099, 43.77897414682188], "dst_loc": [-79.43882692899136, 43.67869192251501]}, {"type": "call", "src_number": "832-2301", "dst_number": "180-2368", "time": "2018-02-08 08:45:40", "duration": 1, "src_loc": [-79.48458771213588, 43.60734949315318], "dst_loc": [-79.37285908877861, 43.66028123543498]}, {"type": "call", "src_number": "095-6518", "dst_number": "469-3515", "time": "2018-02-08 12:37:18", "duration": 102, "src_loc": [-79.5041356538536, 43.70151389216995], "dst_loc": [-79.30075236481127, 43.739914954214754]}, {"type": "sms", "src_number": "373-3350", "dst_number": "142-5525", "time": "2018-02-08 12:40:49", "src_loc": [-79.68567837223472, 43.799100373341695], "dst_loc": [-79.65460763219274, 43.647171771698325]}, {"type": "call", "src_number": "247-2510", "dst_number": "629-5175", "time": "2018-02-08 13:31:58", "duration": 268, "src_loc": [-79.36071074016057, 43.62623314792673], "dst_loc": [-79.53428119890053, 43.58426688443261]}, {"type": "sms", "src_number": "129-8541", "dst_number": "101-7414", "time": "2018-02-08 17:38:02", "src_loc": [-79.5374522025347, 43.63276944373226], "dst_loc": [-79.68951890753074, 43.58192662574493]}, {"type": "sms", "src_number": "784-0925", "dst_number": "247-2510", "time": "2018-02-08 18:22:11", "src_loc": [-79.48218194526196, 43.69738355796221], "dst_loc": [-79.5123567325659, 43.75950115427946]}, {"type": "call", "src_number": "730-5600", "dst_number": "095-6518", "time": "2018-02-09 00:45:13", "duration": 33, "src_loc": [-79.49718244455997, 43.68919467436366], "dst_loc": [-79.33725647479145, 43.73351761372302]}, {"type": "call", "src_number": "744-6324", "dst_number": "013-3456", "time": "2018-02-09 03:10:03", "duration": 102, "src_loc": [-79.55126894300749, 43.79290702300345], "dst_loc": [-79.52123395172768, 43.71302121852292]}, {"type": "sms", "src_number": "938-6680", "dst_number": "100-8771", "time": "2018-02-09 05:14:37", "src_loc": [-79.20791069928809, 43.748437463922244], "dst_loc": [-79.58902493003163, 43.64935712237218]}, {"type": "call", "src_number": "100-8771", "dst_number": "067-3729", "time": "2018-02-09 05:25:10", "duration": 51, "src_loc": [-79.41464659420858, 43.628869185398074], "dst_loc": [-79.48747697407707, 43.66112994680709]}, {"type": "sms", "src_number": "390-1713", "dst_number": "444-0066", "time": "2018-02-09 07:42:08", "src_loc": [-79.34973959681996, 43.72068841815903], "dst_loc": [-79.61490810564082, 43.69386471441907]}, {"type": "sms", "src_number": "849-3472", "dst_number": "006-3878", "time": "2018-02-09 09:57:55", "src_loc": [-79.2760897035372, 43.58352853758888], "dst_loc": [-79.64397786991002, 43.6346018575061]}, {"type": "sms", "src_number": "159-1100", "dst_number": "731-6163", "time": "2018-02-09 18:04:11", "src_loc": [-79.29327314615163, 43.656363360122704], "dst_loc": [-79.56162556707608, 43.71273017212304]}, {"type": "call", "src_number": "731-6163", "dst_number": "942-5962", "time": "2018-02-09 20:26:33", "duration": 347, "src_loc": [-79.4865723985096, 43.63406640145802], "dst_loc": [-79.65494245828853, 43.60544469799307]}, {"type": "call", "src_number": "576-9648", "dst_number": "603-0289", "time": "2018-02-09 23:23:45", "duration": 204, "src_loc": [-79.57199713083054, 43.7455958786449], "dst_loc": [-79.4392800948074, 43.717155440486366]}, {"type": "sms", "src_number": "010-3671", "dst_number": "839-0275", "time": "2018-02-10 01:34:35", "src_loc": [-79.35446719542102, 43.79861474672492], "dst_loc": [-79.33787116763764, 43.668903106517924]}, {"type": "sms", "src_number": "286-6787", "dst_number": "013-3456", "time": "2018-02-10 01:35:31", "src_loc": [-79.62604974172187, 43.693662974186175], "dst_loc": [-79.44413779859205, 43.76810481906296]}, {"type": "sms", "src_number": "744-6324", "dst_number": "067-3729", "time": "2018-02-10 05:11:09", "src_loc": [-79.56641364516517, 43.696612123645124], "dst_loc": [-79.63779729094445, 43.755108735604196]}, {"type": "sms", "src_number": "430-4508", "dst_number": "560-7837", "time": "2018-02-10 05:43:09", "src_loc": [-79.28490853261637, 43.79813409287593], "dst_loc": [-79.51112703335998, 43.71653741116643]}, {"type": "call", "src_number": "099-1900", "dst_number": "101-7414", "time": "2018-02-10 06:48:33", "duration": 269, "src_loc": [-79.31426217305027, 43.746777305148214], "dst_loc": [-79.38373160239351, 43.636734572021275]}, {"type": "sms", "src_number": "178-3378", "dst_number": "469-3515", "time": "2018-02-10 08:23:30", "src_loc": [-79.62866972454897, 43.630010994641694], "dst_loc": [-79.6530129303813, 43.67118923023277]}, {"type": "call", "src_number": "744-6324", "dst_number": "349-5337", "time": "2018-02-10 09:28:14", "duration": 79, "src_loc": [-79.60407893894536, 43.79109927642276], "dst_loc": [-79.42060161800215, 43.60376077486623]}, {"type": "sms", "src_number": "839-7840", "dst_number": "940-6196", "time": "2018-02-10 14:19:59", "src_loc": [-79.64669192776833, 43.7017003287195], "dst_loc": [-79.69204749837195, 43.79565342584212]}, {"type": "call", "src_number": "839-0275", "dst_number": "493-8650", "time": "2018-02-10 14:48:08", "duration": 248, "src_loc": [-79.6507925070743, 43.71761893977619], "dst_loc": [-79.48762564124692, 43.61917976504349]}, {"type": "sms", "src_number": "845-3937", "dst_number": "956-4003", "time": "2018-02-10 16:42:39", "src_loc": [-79.63270489307085, 43.639343699694564], "dst_loc": [-79.60365288687586, 43.76441303525918]}, {"type": "call", "src_number": "095-6518", "dst_number": "496-5543", "time": "2018-02-10 20:49:09", "duration": 159, "src_loc": [-79.60938991021794, 43.597187777240315], "dst_loc": [-79.59369866302585, 43.622894624241766]}, {"type": "call", "src_number": "731-6514", "dst_number": "010-3671", "time": "2018-02-11 04:52:55", "duration": 122, "src_loc": [-79.38607764029744, 43.72272869360939], "dst_loc": [-79.48512645319109, 43.72595738976939]}, {"type": "sms", "src_number": "293-2025", "dst_number": "665-2075", "time": "2018-02-11 05:52:00", "src_loc": [-79.35467407395267, 43.78484212880292], "dst_loc": [-79.5765797866269, 43.76891016383471]}, {"type": "sms", "src_number": "711-1347", "dst_number": "637-0682", "time": "2018-02-11 15:26:18", "src_loc": [-79.6692167063516, 43.58751622823409], "dst_loc": [-79.40028623847388, 43.63337478430788]}, {"type": "call", "src_number": "696-2653", "dst_number": "607-9319", "time": "2018-02-11 23:51:31", "duration": 28, "src_loc": [-79.6260007890523, 43.70511287152723], "dst_loc": [-79.29846050834718, 43.680233117718814]}, {"type": "sms", "src_number": "067-3729", "dst_number": "676-5324", "time": "2018-02-12 02:02:12", "src_loc": [-79.69508888803169, 43.76791880666186], "dst_loc": [-79.40911536012534, 43.685375650174215]}, {"type": "call", "src_number": "493-8650", "dst_number": "300-7295", "time": "2018-02-12...