From 312a27521ce8b9f4121fe10d49b93e3db7dd0f6e Mon Sep 17 00:00:00 2001 From: MassiveAtoms Date: Mon, 8 Jul 2019 17:57:09 -0300 Subject: [PATCH] added telephone support --- .clang-format | 2 +- Customer.cpp | 53 ++++++++++++++++++++------------------------ Interface.cpp | 41 +++++++++++++++++++++++++++++----- Park_spot.cpp | 6 ++--- Park_time.cpp | 18 +++++---------- Query.cpp | 53 +++++++++++++++++++++----------------------- data.cpp | 7 ++---- encrypt.cpp | 10 +++------ headers/Customer.h | 11 +++++---- headers/Interface.h | 7 +++--- headers/Park_spot.h | 2 +- headers/Park_time.h | 15 ++++++------- headers/Query.h | 11 ++++----- headers/data.h | 4 ++-- headers/encrypt.h | 8 +++---- main.cpp | 5 ----- oldtest.db3 | Bin 0 -> 16384 bytes test.db3 | Bin 16384 -> 16384 bytes 18 files changed, 128 insertions(+), 125 deletions(-) create mode 100644 oldtest.db3 diff --git a/.clang-format b/.clang-format index 64937c3..3481df7 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,7 @@ IndentWidth: 4 Language: Cpp PointerAlignment: Left -ColumnLimit: 80 +ColumnLimit: 100 AlignAfterOpenBracket: Align AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true diff --git a/Customer.cpp b/Customer.cpp index 3d7a8a3..7bb5e8b 100644 --- a/Customer.cpp +++ b/Customer.cpp @@ -1,19 +1,24 @@ #include "headers/Customer.h" + // constructors -Customer::Customer(string name_, string password_, Vehicle_type vehicle_) - : name{name_}, vehicle{vehicle_}, password{hash_password(password_)} { - id = auto_increment_db() + 1; +Customer::Customer(string name_, string password_, Vehicle_type vehicle_, string telephone_) + : id{auto_increment_db() + 1}, + name{name_}, + password{hash_password(password_)}, + vehicle{vehicle_}, + telephone{telephone_} { save_db(); } -Customer::Customer(int id_, string name_, string password_, - Vehicle_type vehicle_, vector instances) +Customer::Customer(int id_, string name_, string password_, Vehicle_type vehicle_, + vector instances, string telephone_) : id{id_}, name{name_}, password{password_}, vehicle{vehicle_}, - park_instances{instances} {} + park_instances{instances}, + telephone{telephone_} {} // clock in/out methods // ==================================================================================== @@ -31,41 +36,27 @@ void Customer::clock_out(int s_id) { } bool Customer::parked() { - if (!park_instances.size()){ + if (!park_instances.size()) { return false; } if ((park_instances[park_instances.size() - 1].duration)) { // if duration of the last parktime == 0, meaning // that the customer has not clocked out return false; - } - else { + } else { return true; } } -int Customer::parked_at(){ - return park_instances[park_instances.size() - 1].spot_id; -} - -// report gen -void Customer::gen_monthly() { - cout << "NAME: " << name << "\n"; - cout << "-------------------------------------------------\n"; - for (auto& i : park_instances) { - // TODO: need some logic to only include from this month. scratch that, - // need to remove gen monthly - cout << i; - } - cout << "-------------------------------------------------\n\n"; -} +int Customer::parked_at() { return park_instances[park_instances.size() - 1].spot_id; } //================================================================================================ // functions that interact with the database void Customer::save_db() { - string statement{"insert into Customer values (, '', '', );"}; + string statement{"insert into Customer values (, '', '', , );"}; // after ( = 28) + statement.insert(40, telephone); statement.insert(38, to_string(int(vehicle))); statement.insert(36, password); statement.insert(32, name); @@ -77,11 +68,15 @@ void Customer::save_db() { void Customer::update_db() { string statement = - "UPDATE Customer SET name = '', card_code = '' where id = '';"; - statement.insert(58, to_string(id)); - statement.insert(44, password); + "UPDATE Customer SET name = '', password = '', " + "vehicle = '', telephone = '' where id = '';"; + statement.insert(87, to_string(id)); + statement.insert(73, telephone); + statement.insert(57, to_string(int(vehicle))); + statement.insert(43, password); statement.insert(28, name); - data::db.exec(statement); + cout << statement; + // data::db.exec(statement); } void Customer::delete_db() { diff --git a/Interface.cpp b/Interface.cpp index 92b1e36..0335ee3 100644 --- a/Interface.cpp +++ b/Interface.cpp @@ -47,7 +47,7 @@ void interface_member(vector& spots) { break; } case 2: { - c.gen_monthly(); + cout << "Has not been implemented yet\n"; break; } @@ -63,7 +63,8 @@ void interface_admin(vector& spots) { cout << "[3] See monthly report of a specific parking spot\n"; cout << "[4] See weekly report of a specific parking spot\n"; cout << "[5] See current status of parking spots\n"; - cout << "option[1-5]:"; + cout << "[6] Make new customer\n"; + cout << "option[1-6]:"; int option; cin >> option; switch (option) { @@ -92,6 +93,12 @@ void interface_admin(vector& spots) { case 5: { current_status_parkspots(spots); } + case 6: { + new_customer(); + } + case 7: { + new_parkspot(spots); + } default: break; @@ -122,9 +129,8 @@ void park(Customer& c, vector& spots) { } } else { - cout - << "You are parked at spot " << c.parked_at() - << ", do you want to clock out?\n enter [1] for yes and [0] for no"; + cout << "You are parked at spot " << c.parked_at() + << ", do you want to clock out?\n enter [1] for yes and [0] for no"; int answer = 0; cin >> answer; if (answer) { @@ -134,4 +140,29 @@ void park(Customer& c, vector& spots) { cout << "OK, have a nice day"; } } +} + +void new_customer() { + int vtype; + string name; + string password; + string telephone; + cout << "What's the name of the customer? "; + cin >> name; + cout << "What's the vehicle type? [1]twoweeler, [2] fourweeler: "; + cin >> vtype; + cout << "What's the telephone number? "; + cin >> telephone; + cout << "What's the password? "; + cin >> password; + Customer newcustomer{name, password, Vehicle_type(vtype), telephone}; + cout << "New customer sucessfully created\n"; +} + +void new_parkspot(vector& spots) { + cout << "What type of parking spot? [1] twoweeler, [2] fourweeler: "; + int vtype; + Park_spot newspot{Vehicle_type(vtype)}; + spots.push_back(newspot); + cout << "new parking spot sucessfully created.\n"; } \ No newline at end of file diff --git a/Park_spot.cpp b/Park_spot.cpp index 7efc6cf..3850484 100644 --- a/Park_spot.cpp +++ b/Park_spot.cpp @@ -7,14 +7,13 @@ Park_spot::Park_spot(Vehicle_type v_type_) save_db(); } -Park_spot::Park_spot(int id_, bool taken_, int parked,Vehicle_type v_type_) +Park_spot::Park_spot(int id_, bool taken_, int parked, Vehicle_type v_type_) : parked_customer{parked}, id{id_}, v_type{v_type_}, taken{taken_} // TODO: think about how init parked? {} - // clock in en out, calls de juist(in/out) van de customer aan de hand van // internal state van taken void Park_spot::clock(Customer& c_customer) { @@ -34,8 +33,7 @@ void Park_spot::clock(Customer& c_customer) { // --------------------- db functs void Park_spot::update_db() { - string statement = - "UPDATE Park_spot SET taken = '', customer_id = '' where id = '';"; + string statement = "UPDATE Park_spot SET taken = '', customer_id = '' where id = '';"; statement.insert(63, to_string(id)); if (taken) { statement.insert(49, to_string(parked_customer)); diff --git a/Park_time.cpp b/Park_time.cpp index 0da71ea..771133d 100644 --- a/Park_time.cpp +++ b/Park_time.cpp @@ -17,14 +17,11 @@ Park_time::Park_time(int c_id, int s_id) save_db(); } /* -this one initializes with data from the database. should probably only be used in the query functions. +this one initializes with data from the database. should probably only be used in the query +functions. */ -Park_time::Park_time(int id_, int customer_id_, int spot_id_, int start_, - int duration_) - : id{id_}, - customer_id{customer_id_}, - spot_id{spot_id_}, - duration{duration_} { +Park_time::Park_time(int id_, int customer_id_, int spot_id_, int start_, int duration_) + : id{id_}, customer_id{customer_id_}, spot_id{spot_id_}, duration{duration_} { start = time_point(seconds(start_)); end = time_point(seconds(start_ + duration_)); } @@ -48,8 +45,7 @@ void Park_time::clock_out(int c_id, int s_id) { if (!duration) { end = high_resolution_clock::now(); - duration = - duration_cast(end - start).count(); // use mins later + duration = duration_cast(end - start).count(); // use mins later update_db(); } else { @@ -97,8 +93,7 @@ void Park_time::save_db() { } // same as above void Park_time::update_db() { - string statement = - "UPDATE Park_time SET end = , duration = where id = '';"; + string statement = "UPDATE Park_time SET end = , duration = where id = '';"; statement.insert(53, to_string(id)); statement.insert(40, to_string(duration)); statement.insert(27, to_string(start_to_int() + duration)); @@ -115,7 +110,6 @@ int Park_time::auto_increment_db() { return id; } - //------------------ test function to help test this void Wait(int sec) diff --git a/Query.cpp b/Query.cpp index 6bdbd2a..8fcc5b0 100644 --- a/Query.cpp +++ b/Query.cpp @@ -8,8 +8,7 @@ vector query_parktimes_for_customer(int cid) { */ vector park_times; - SQLite::Statement query(data::db, - "SELECT * FROM Park_time WHERE customer_id = ?;"); + SQLite::Statement query(data::db, "SELECT * FROM Park_time WHERE customer_id = ?;"); query.bind(1, cid); while (query.executeStep()) { int id = query.getColumn(0); @@ -33,18 +32,18 @@ vector query_customer_with_name(string name) { 2. multiple customers could be returned with the same name. */ vector result; - SQLite::Statement query( - data::db, - "SELECT id, name, password, vehicle FROM Customer WHERE name = ?;"); + SQLite::Statement query(data::db, + "SELECT id, name, password, vehicle FROM Customer WHERE name = ?;"); query.bind(1, name); while (query.executeStep()) { int id = query.getColumn(0); string name_ = query.getColumn(1); string password = query.getColumn(2); int vehicle = query.getColumn(3); // cast to vehicle + string telephone = query.getColumn(4); vector park_instances = query_parktimes_for_customer(id); - result.push_back(Customer{ - id, name_, password, Vehicle_type(vehicle), park_instances}); + result.push_back( + Customer{id, name_, password, Vehicle_type(vehicle), park_instances, telephone}); } return result; } @@ -63,9 +62,9 @@ Customer query_customer_with_id(int id) { string name = query.getColumn(1); string password = query.getColumn(2); int vehicle = query.getColumn(3); // cast to vehicle + string telephone = query.getColumn(4); vector park_instances = query_parktimes_for_customer(id); - Customer result{ - id, name, password, Vehicle_type(vehicle), park_instances}; + Customer result{id, name, password, Vehicle_type(vehicle), park_instances, telephone}; // DEBUG // cout << "{" << result.id << "," <& parkspots) { void reports_from_parkspot(int spotid, bool weekly) { std::time_t t = std::time(0); // get time now std::tm* now = std::localtime(&t); - int s_since_epoch = ((now->tm_year - 70) * 365.2425 * 24 * 3600) + - (now->tm_mon * 30.436875 * 24 * 3600); - if (weekly){ - s_since_epoch += ((now->tm_mday/ 7) * 24 * 3600); + if (weekly) { + now->tm_wday = 1; + } else { + now->tm_mday = 1; } + int s_since_epoch = mktime(now); + vector park_times; - SQLite::Statement query( - data::db, "SELECT * FROM Park_time WHERE spot_id = ? AND start > ?;"); + SQLite::Statement query(data::db, "SELECT * FROM Park_time WHERE spot_id = ? AND start > ?;"); query.bind(1, spotid); query.bind(2, s_since_epoch); while (query.executeStep()) { @@ -113,19 +113,19 @@ void reports_from_parkspot(int spotid, bool weekly) { } } - void reports_from_allparkspots(bool weekly) { std::time_t t = std::time(0); // get time now std::tm* now = std::localtime(&t); - int s_since_epoch = ((now->tm_year - 70) * 365.2425 * 24 * 3600) + - (now->tm_mon * 30.436875 * 24 * 3600); - if (weekly){ - s_since_epoch += ((now->tm_mday/ 7) * 24 * 3600); + if (weekly) { + now->tm_wday = 1; + } else { + now->tm_mday = 1; } + int s_since_epoch = mktime(now); + vector park_times; - SQLite::Statement query( - data::db, "SELECT * FROM Park_time WHERE start > ?;"); + SQLite::Statement query(data::db, "SELECT * FROM Park_time WHERE start > ?;"); query.bind(1, s_since_epoch); while (query.executeStep()) { int id = query.getColumn(0); @@ -143,15 +143,12 @@ void reports_from_allparkspots(bool weekly) { } } - - - -void current_status_parkspots(vector& spots){ - for(auto& i : spots){ +void current_status_parkspots(vector& spots) { + for (auto& i : spots) { cout << "---------------------------\n"; cout << "PS #" << i.id << "\n"; cout << "Taken: " << ((i.taken) ? "true" : "false") << "\n"; - if (i.taken){ + if (i.taken) { cout << "Customer#" << i.parked_customer << " parked there\n"; } } diff --git a/data.cpp b/data.cpp index 5c000b9..91b9033 100644 --- a/data.cpp +++ b/data.cpp @@ -6,8 +6,7 @@ SQLite::Database start_db() { /* Opens the database, creates it if it can't find the file. */ - SQLite::Database db("test.db3", - SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); while (sodium_init() < 0) { std::cout << "SODIUM NOT WORKING"; /* @@ -17,11 +16,9 @@ SQLite::Database start_db() { with any libsodium function. */ } - //sql syntax is surprisingly readable. db.exec( "create table if not exists Customer (id integer primary key, name " - "text, password text, vehicle int)"); - // getting errors when using bool, so i used an int instead. + "text, password text, vehicle int, telephone text)"); db.exec( "create table if not exists Park_spot (id integer primary key, taken " "int, customer_id int, vehicle_type int)"); diff --git a/encrypt.cpp b/encrypt.cpp index 591a2c4..06b5a90 100644 --- a/encrypt.cpp +++ b/encrypt.cpp @@ -15,11 +15,8 @@ string hash_password(string password) { int memory_limit = 3.2e+7; // 3.2e7 = 32e6 = 32 mb int cpu_limit = 1; // this is n_threads - int result = crypto_pwhash_str(hashed_password_, - password_, - strlen(password_), - cpu_limit, - memory_limit); + int result = + crypto_pwhash_str(hashed_password_, password_, strlen(password_), cpu_limit, memory_limit); string hashed_password{hashed_password_}; return hashed_password; @@ -32,8 +29,7 @@ bool verify_password(string hashed_password, string unhashed_password) { const char* password_ = unhashed_password.c_str(); const char* hashed_password_ = hashed_password.c_str(); - if (crypto_pwhash_str_verify( - hashed_password_, password_, strlen(password_)) != 0) { + if (crypto_pwhash_str_verify(hashed_password_, password_, strlen(password_)) != 0) { return false; } else { return true; diff --git a/headers/Customer.h b/headers/Customer.h index ce02737..a457f80 100644 --- a/headers/Customer.h +++ b/headers/Customer.h @@ -16,7 +16,7 @@ hood, it's still an int. This is here so you won't have to have global variables for these categories, or worse, use magic numbers in the code. */ -enum class Vehicle_type { bike = 1, small_car = 2, suv = 3, pickup = 4 }; +enum class Vehicle_type { twoweeler = 1, fourweeler = 2 }; /* Customer constructors do the same stuff as all the other constructors. @@ -38,9 +38,11 @@ class Customer { int id; string name; string password; - Customer(string name_, string password_, Vehicle_type vehicle_); + Vehicle_type vehicle; + string telephone; + Customer(string name_, string password_, Vehicle_type vehicle_, string telephone_); Customer(int id_, string name_, string password_, Vehicle_type vehicle_, - vector instances); + vector instances, string telephone_); void clock_in(int s_id); void clock_out(int s_id); bool parked(); @@ -49,9 +51,6 @@ class Customer { void update_db(); void delete_db(); - void gen_monthly(); - Vehicle_type vehicle; - private: vector park_instances; void save_db(); diff --git a/headers/Interface.h b/headers/Interface.h index bb59a17..7051928 100644 --- a/headers/Interface.h +++ b/headers/Interface.h @@ -2,11 +2,12 @@ #include "Query.h" + using std::cin; - - void interface(vector& spots); void interface_member(vector& spots); void interface_admin(vector& spots); -void park(Customer& c, vector& spots); \ No newline at end of file +void park(Customer& c, vector& spots); +void new_customer(); +void new_parkspot(vector& spots); \ No newline at end of file diff --git a/headers/Park_spot.h b/headers/Park_spot.h index 068fc55..d4ebf92 100644 --- a/headers/Park_spot.h +++ b/headers/Park_spot.h @@ -19,7 +19,7 @@ class Park_spot { bool taken; int parked_customer; Vehicle_type v_type; - + Park_spot(Vehicle_type v_type_); Park_spot(int id_, bool taken_, int parked, Vehicle_type v_type_); void clock(Customer& c_customer); diff --git a/headers/Park_time.h b/headers/Park_time.h index 550ad5c..322ceeb 100644 --- a/headers/Park_time.h +++ b/headers/Park_time.h @@ -5,10 +5,10 @@ #include "data.h" #include -#include #include #include #include +#include using namespace std::chrono; using std::cout; @@ -32,21 +32,21 @@ operator<< is << overload, can(should) be used for report generation. // implementation stuff------------------------ -start and end are time points representing when someone clocks in and out. they're from the chrono namespace. +start and end are time points representing when someone clocks in and out. they're from the chrono +namespace. save and update save and update info in the database. auto_increment pulls the highest id stored in the db, to be used in the constructor. -start_to_int() is used to convert the start timepoint to an integer that can be saved in the database -SQL datetime and chrono datetime don't seem the most compatible. +start_to_int() is used to convert the start timepoint to an integer that can be saved in the +database SQL datetime and chrono datetime don't seem the most compatible. */ class Park_time { public: Park_time(int c_id, int s_id); - Park_time(int id_, int customer_id_, int spot_id_, int start_, - int duration_); + Park_time(int id_, int customer_id_, int spot_id_, int start_, int duration_); int id; int customer_id; int spot_id; @@ -64,8 +64,7 @@ class Park_time { int start_to_int(); // helper }; - -//test funciton +// test funciton void Wait(int sec); #endif // Park_time \ No newline at end of file diff --git a/headers/Query.h b/headers/Query.h index 703ebf1..61e33f5 100644 --- a/headers/Query.h +++ b/headers/Query.h @@ -26,7 +26,7 @@ customers who have the same name. 2. I have no clue how many of you have done error handling in c++ (try/catch/finally). Ya boi is nice and doesn't want to bombard you with more new concepts than needed. -so now you'd do +so now you'd do vector test = query_customer_with_name("Testman"); @@ -34,7 +34,7 @@ if (!test.size()) {print no customers found, do stuff} else if (test.size() > 1) { do stuff to get the right one if you only need one } -instead of +instead of try { customer test = query_customer_with_name("Testman"); } @@ -46,7 +46,8 @@ finally{ do more stuff } -3. Ya boi needs to brush up on how to create custom exceptions class, and it will complicate code furhter. +3. Ya boi needs to brush up on how to create custom exceptions class, and it will complicate code +furhter. */ @@ -59,8 +60,8 @@ vector populate_spots(); Park_spot query_parkspot_with_id(int id, vector& parkspots); -void reports_from_parkspot(int spotid, bool weekly=false); -void reports_from_allparkspots(bool weekly=false); +void reports_from_parkspot(int spotid, bool weekly = false); +void reports_from_allparkspots(bool weekly = false); void current_status_parkspots(vector& spots); #endif // CUSTOMER_H diff --git a/headers/data.h b/headers/data.h index 502106c..0266d53 100644 --- a/headers/data.h +++ b/headers/data.h @@ -8,8 +8,8 @@ namespace data { /* start_db is the function that opens the database, and -if the necesary tables are not there, creates them. -db is the database, and is static to avoid multiple redefinition errors. +if the necesary tables are not there, creates them. +db is the database, and is static to avoid multiple redefinition errors. */ SQLite::Database start_db(); static SQLite::Database db = start_db(); diff --git a/headers/encrypt.h b/headers/encrypt.h index 8377ddc..4fcc6e5 100644 --- a/headers/encrypt.h +++ b/headers/encrypt.h @@ -10,11 +10,11 @@ using std::string; /* hash_password takes the password, and encrypts it. This needs to be done, -because storing passwords in plaintext is BAD! +because storing passwords in plaintext is BAD! -verify_password takes in a password and the hashed password, and then does magic encryption stuff(no, not -really. It basically hashes the password with the same salt and other -parameters) and to see if the password stored and the given password match. +verify_password takes in a password and the hashed password, and then does magic encryption +stuff(no, not really. It basically hashes the password with the same salt and other parameters) and +to see if the password stored and the given password match. */ string hash_password(string password); diff --git a/main.cpp b/main.cpp index 6f95bac..596b79c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,5 @@ #include "headers/Interface.h" - - - /* Code structure is like this: 1. encrypt.cpp en /header/encrypt.h contain functions to hash passwords and @@ -52,8 +49,6 @@ int main() { // er is een customer met id 1(testcustomer) met password "password" interface(parking_spots); - - } /* diff --git a/oldtest.db3 b/oldtest.db3 new file mode 100644 index 0000000000000000000000000000000000000000..4f0d862b3822636639be2e808bc7fa919ed1fc15 GIT binary patch literal 16384 zcmeI%L2nX46bJAbc7bk_GOf|{)OJ!a(S)d!*2;lIYzc{yB3eiqLz-=w;tI>+?i5<1 z2hRExOix}sYdm@LU}A6H^ybm%!J{{4S!ipt-kO;BpD>wuZ-;p^zZ=V)Qo)jfZ#k}Q zN}eL)gi>;ib3(|p>bmN~rm4x%m<}KOWt=7#=lPggpv4{&_LRlcfCd2wKmY;|fB*y_ z009U<00RG;Krg06Cue48uOZEirnqIgjdf|+hZBA2b}qY`0g&aS4&d*ylZndPS z3zxTD%QoFz-VnP9zPas5#}@8-upq&`wj&P%X}Z$?VuFiSe}@FGZM&wloR*)y@F*0V zCx3Vze}jHuf1>?<9zT8jd8FA8{jL9Sw2ruEZ8pWa+--|~b(cmbr>1Ccv0r^@aFyX0 z`la?Tdwl7ZX$vmJj=F5y^t`U))&}9AaKEPi+nll|M19a8009U<00Izz00bZa0SG_< z0uVTP0gpz=xn9wb!jr@I7;)3BJFPjZ7Vl(|>A0OqCFd3{CuAm>XlIh~N+o^2UT$=5 zmb%Gg<5I3zT5i_r@tv!=RQkrsL#JC5tJzd-=RsxJU76o#X4A`FvC!$3n`U+`y;T=$ zW9$nVWqX9}vG42!`^-ME4{V>kWpCK4lfN=5KmY;|fB*y_009U<00Izz00bbQ1PmG` zBWH}2a-m>o2h+%?ni8sq4SzHuBZDv+gpolQ4njQ$*$)ym3?mW>LbbUc`v3py>?L8} z*hltGP0%0!0SG_<0uX=z1Rwwb2tWV=5cnqqPU%tgVnEkJT6K1zU7fx1n&!tfl{0jm hR{4Hj^}DAhLcuDkRr&j`Ds^^of*wgdQ|ad;KLH|w*0=xw literal 0 HcmV?d00001 diff --git a/test.db3 b/test.db3 index 4f0d862b3822636639be2e808bc7fa919ed1fc15..48e8b132829772fd943c45f7cb1feeff1dbd8156 100644 GIT binary patch delta 320 zcmZo@U~Fh$oFL7}K2gS5n4Lk-M1hxqfq|JXhk?JE?=N4@#>QW~n``;_8Mzvn7}>>T zWf>d8Cr{w+EG06t*xy*& zH^M!!!ra_DAj=@qR6jE`Hz2>nqN3Q;(%iz_$lS=tvYZiOyzu17^4ftVp`lKRZrKG{ zB^8M|k+~)*!Ja8a7=EX(^#?FD|VaAq4`VoGK=Gh*}0hNVj?xF4m v&Q2vE20)V`e)z<||C9gIW{bd0o2OHYmD z<$uM%#Xp~ce?I?5{#E>s_;2%H=0C%KgnuvpR-lE={PmoStPC8YoPMD`KAg;OCL0%! z$-v0M$_b)5**KtFb_kaZ%4LOcSs+~gpA77roSbY-5H8SXATG#