Help | Site Map
Connecting Tech Pros Worldwide
 
 
LinkBack Thread Tools
  #1  
Old December 5th, 2006, 05:15 PM
B. Williams
Guest
 
Posts: n/a
Default Assistance with linked lists

I have written some code to accept input and place this input at the
beginning or end of a list, but I need assistance including a class so that
it will allow input of a phone number that is properly formatted. I'll post
my code below. Thanks in advance.

This is the code for the linked list. It tests using int's and string's.

#ifndef LIST_H
#define LIST_H

#include <iostream>
using std::cout;

#include "Listnode.h"

template< typename NODETYPE >
class List
{
public:
List();
~List();
void insertAtFront( const NODETYPE & );
void insertAtBack( const NODETYPE & );
bool removeFromFront( NODETYPE & );
bool removeFromBack( NODETYPE & );
bool isEmpty() const;
void print() const;
private:
ListNode< NODETYPE *firstPtr;
ListNode< NODETYPE *lastPtr;

// utility function to allocate new node
ListNode< NODETYPE *getNewNode( const NODETYPE & );
}; // end class List

// default constructor
template< typename NODETYPE >
List< NODETYPE >::List()
: firstPtr( 0 ), lastPtr( 0 )
{
}

// destructor
template< typename NODETYPE >
List< NODETYPE >::~List()
{
if ( !isEmpty() ) // List is not empty
{
cout << "Destroying nodes ...\n";

ListNode< NODETYPE *currentPtr = firstPtr;
ListNode< NODETYPE *tempPtr;

while ( currentPtr != 0 ) // delete remaining nodes
{
tempPtr = currentPtr;
cout << tempPtr->data << '\n';
currentPtr = currentPtr->nextPtr;
delete tempPtr;
} // end while
} // end if

cout << "All nodes destroyed\n\n";
} // end List destructor

// insert node at front of list
template< typename NODETYPE >
void List< NODETYPE >::insertAtFront( const NODETYPE &value )
{
ListNode< NODETYPE *newPtr = getNewNode( value ); // new node

if ( isEmpty() ) // List is empty
firstPtr = lastPtr = newPtr; // new list has only one node
else // List is not empty
{
newPtr->nextPtr = firstPtr; // point new node to previous 1st node
firstPtr = newPtr; // aim firstPtr at new node
} // end else
} // end function insertAtFront

// insert node at back of list
template< typename NODETYPE >
void List< NODETYPE >::insertAtBack( const NODETYPE &value )
{
ListNode< NODETYPE *newPtr = getNewNode( value ); // new node

if ( isEmpty() ) // List is empty
firstPtr = lastPtr = newPtr; // new list has only one node
else // List is not empty
{
lastPtr->nextPtr = newPtr; // update previous last node
lastPtr = newPtr; // new last node
} // end else
} // end function insertAtBack

// delete node from front of list
template< typename NODETYPE >
bool List< NODETYPE >::removeFromFront( NODETYPE &value )
{
if ( isEmpty() ) // List is empty
return false; // delete unsuccessful
else
{
ListNode< NODETYPE *tempPtr = firstPtr; // hold tempPtr to delete

if ( firstPtr == lastPtr )
firstPtr = lastPtr = 0; // no nodes remain after removal
else
firstPtr = firstPtr->nextPtr; // point to previous 2nd node

value = tempPtr->data; // return data being removed
delete tempPtr; // reclaim previous front node
return true; // delete successful
} // end else
} // end function removeFromFront

// delete node from back of list
template< typename NODETYPE >
bool List< NODETYPE >::removeFromBack( NODETYPE &value )
{
if ( isEmpty() ) // List is empty
return false; // delete unsuccessful
else
{
ListNode< NODETYPE *tempPtr = lastPtr; // hold tempPtr to delete

if ( firstPtr == lastPtr ) // List has one element
firstPtr = lastPtr = 0; // no nodes remain after removal
else
{
ListNode< NODETYPE *currentPtr = firstPtr;

// locate second-to-last element
while ( currentPtr->nextPtr != lastPtr )
currentPtr = currentPtr->nextPtr; // move to next node

lastPtr = currentPtr; // remove last node
currentPtr->nextPtr = 0; // this is now the last node
} // end else

value = tempPtr->data; // return value from old last node
delete tempPtr; // reclaim former last node
return true; // delete successful
} // end else
} // end function removeFromBack

// is List empty?
template< typename NODETYPE >
bool List< NODETYPE >::isEmpty() const
{
return firstPtr == 0;
} // end function isEmpty

// return pointer to newly allocated node
template< typename NODETYPE >
ListNode< NODETYPE *List< NODETYPE >::getNewNode(
const NODETYPE &value )
{
return new ListNode< NODETYPE >( value );
} // end function getNewNode

// display contents of List
template< typename NODETYPE >
void List< NODETYPE >::print() const
{
if ( isEmpty() ) // List is empty
{
cout << "The list is empty\n\n";
return;
} // end if

ListNode< NODETYPE *currentPtr = firstPtr;

cout << "The list is: ";

while ( currentPtr != 0 ) // get element data
{
cout << currentPtr->data << ' ';
currentPtr = currentPtr->nextPtr;
} // end while

cout << "\n\n";
} // end function print

#endif

#ifndef LISTNODE_H
#define LISTNODE_H


template< typename NODETYPE class List;

template< typename NODETYPE >
class ListNode
{
friend class List< NODETYPE >;

public:
ListNode( const NODETYPE & );
NODETYPE getData() const;
private:
NODETYPE data;
ListNode< NODETYPE *nextPtr; // next node in list
}; // end class ListNode

// constructor
template< typename NODETYPE >
ListNode< NODETYPE >::ListNode( const NODETYPE &info )
: data( info ), nextPtr( 0 )
{
} // end ListNode constructor

// return copy of data in node
template< typename NODETYPE >
NODETYPE ListNode< NODETYPE >::getData() const
{
return data;
} // end function getData

#endif

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <string>
using std::string;

#include "List.h"

// function to test a List
template< typename T >
void testList( List< T &listObject, const string &typeName )
{
cout << "Testing a List of " << typeName << " values\n";
instructions(); // display instructions

int choice; // store user choice
T value; // store input value

do // perform user-selected actions
{
cout << "? ";
cin >choice;

switch ( choice )
{
case 1: // insert at beginning
cout << "Enter " << typeName << ": ";
cin >value;
listObject.insertAtFront( value );
listObject.print();
break;
case 2: // insert at end
cout << "Enter " << typeName << ": ";
cin >value;
listObject.insertAtBack( value );
listObject.print();
break;
case 3: // remove from beginning
if ( listObject.removeFromFront( value ) )
cout << value << " removed from list\n";

listObject.print();
break;
case 4: // remove from end
if ( listObject.removeFromBack( value ) )
cout << value << " removed from list\n";

listObject.print();
break;
} // end switch
} while ( choice != 5 ); // end do...while

cout << "End list test\n\n";
} // end function testList


void instructions()
{
cout << "Enter one of the following:\n"
<< " 1 to insert at beginning of list\n"
<< " 2 to insert at end of list\n"
<< " 3 to delete from beginning of list\n"
<< " 4 to delete from end of list\n"
<< " 5 to end list processing\n";
} // end function instructions

int main()
{
// test List of int values
List< int intList;
testList( intList, "integer" );

// test List of string values
List< string stringList;
testList( stringList, "string" );

return 0;
} // end main

I want to be able to include my phone number class so that this will accept
phone numbers as input. Here is the phone class

#ifndef PHONENUMBER_H
#define PHONENUMBER_H

#include <iostream>
using std::ostream;
using std::istream;

#include <string>
using std::string;

#include <iomanip>
using std::setw;

class PhoneNumber
{
friend ostream &operator<<( ostream &, const PhoneNumber & );
friend istream &operator>>( istream &, PhoneNumber & );
private:
string areaCode; // 3-digit area code
string exchange; // 3-digit exchange
string line; // 4-digit line
}; // end class PhoneNumber

ostream &operator<<( ostream &output, const PhoneNumber &number )
{
output << "(" << number.areaCode << ") "
<< number.exchange << "-" << number.line;
return output; // enables cout << a << b << c;
} // end function operator<<

istream &operator>>( istream &input, PhoneNumber &number )
{
input.ignore(); // skip (
input >setw( 3 ) >number.areaCode; // input area code
input.ignore( 2 ); // skip ) and space
input >setw( 3 ) >number.exchange; // input exchange
input.ignore(); // skip dash (-)
input >setw( 4 ) >number.line; // input line
return input; // enables cin >a >b >c;
} // end function operator>>

#endif


  #2  
Old December 5th, 2006, 05:15 PM
Alf P. Steinbach
Guest
 
Posts: n/a
Default Re: Assistance with linked lists

* B. Williams:
Quote:
I need assistance including a class so that
it will allow input of a phone number that is properly formatted.
Try to be a little more specific. Do you want someone to write the code
for you?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
  #3  
Old December 5th, 2006, 06:25 PM
B. Williams
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


"Alf P. Steinbach" <alfps@start.nowrote in message
news:4tlparF149ndqU1@mid.individual.net...
Quote:
>* B. Williams:
Quote:
>I need assistance including a class so that it will allow input of a
>phone number that is properly formatted.
>
Try to be a little more specific. Do you want someone to write the code
for you?
>
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
I apologize for not being more specific. I know both of these work
independently, but I need help with incoporating the phone number class into
the program. I couldn't figure out any better way to get the program to
accept phone numbers. I tried inputting the phone number as a string, but
the blank space ends the string. I guess I am asking for some assistance on
writing the code, but I just need a kick start. This is the code to test the
phone number class.

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

#include "PhoneNumber.h"

int main()
{
PhoneNumber phone;

cout << "Enter phone number in the form (123) 456-7890:" << endl;

cin >phone;

cout << "The phone number entered was: ";

cout << phone << endl;
return 0;
} // end main.


  #4  
Old December 5th, 2006, 09:45 PM
Marcus Kwok
Guest
 
Posts: n/a
Default Re: Assistance with linked lists

B. Williams <willdrama@hotmail.comwrote:
Quote:
I tried inputting the phone number as a string, but
the blank space ends the string.
Try using std::getline() instead.

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
  #5  
Old December 5th, 2006, 10:55 PM
Jim Langston
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


"B. Williams" <willdrama@hotmail.comwrote in message
news:B4jdh.3499$lI6.1007@newsfe13.lga...
Quote:
>
"Alf P. Steinbach" <alfps@start.nowrote in message
news:4tlparF149ndqU1@mid.individual.net...
Quote:
>>* B. Williams:
Quote:
>>I need assistance including a class so that it will allow input of a
>>phone number that is properly formatted.
>>
>Try to be a little more specific. Do you want someone to write the code
>for you?
>>
>--
>A: Because it messes up the order in which people normally read text.
>Q: Why is it such a bad thing?
>A: Top-posting.
>Q: What is the most annoying thing on usenet and in e-mail?
>
I apologize for not being more specific. I know both of these work
independently, but I need help with incoporating the phone number class
into the program. I couldn't figure out any better way to get the program
to accept phone numbers. I tried inputting the phone number as a string,
but the blank space ends the string. I guess I am asking for some
assistance on writing the code, but I just need a kick start. This is the
code to test the phone number class.
>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
>
#include "PhoneNumber.h"
>
int main()
{
PhoneNumber phone;
>
cout << "Enter phone number in the form (123) 456-7890:" << endl;
>
cin >phone;
>
cout << "The phone number entered was: ";
>
cout << phone << endl;
return 0;
} // end main.
And what happens when you run this code? I see you have
operator<< and operator>overridden for the class PhoneNumber and without
looking at the code real closely or testing it, it looks about right. So
what's the problem when you try this?


  #6  
Old December 6th, 2006, 12:25 AM
BobR
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


B. Williams wrote in message ...
Quote:
>
>"Alf P. Steinbach" <alfps@start.nowrote in message ...
Quote:
>Try to be a little more specific. Do you want someone to write the code
>for you?
>
>I apologize for not being more specific. I know both of these work
>independently, but I need help with incoporating the phone number class into
>the program. I couldn't figure out any better way to get the program to
>accept phone numbers. I tried inputting the phone number as a string, but
>the blank space ends the string. I guess I am asking for some assistance on
>writing the code, but I just need a kick start. This is the code to test the
>phone number class.
>
>#include <iostream>
>using std::cout;
>using std::cin;
>using std::endl;
>#include "PhoneNumber.h"
// suggestion:
istream& operator>>( istream &input, PhoneNumber &number ){
std::string line;
std::getline( input, line );
if( /* check something */ ){ /* do something */ } // like 'line.empty()'

if( '(' == line.at(0) && ')' == line.at(4) ){
number.areaCode = line.substr( 1, 3 ); // input area code
}
else{
number.areaCode = "GIGO";
}
number.exchange = line.substr( 6, 3 ); // input exchange
// etc.

// OR:

if( '(' == input.peek() ){
input.ignore();
}
if( input ){
input >number.areaCode;
if( ')' == number.areaCode.at(3) ){
number.areaCode.erase(3);
}
}
// etc.

return input; // enables cin >a >b >c;
} // end function operator>>
Quote:
>
>int main(){
PhoneNumber phone;
cout << "Enter phone number in the form (123) 456-7890:" << endl;
cin >phone;
cout << "The phone number entered was: ";
cout << phone << endl;
return 0;
>} // end main.
--
Bob R
POVrookie


  #7  
Old December 6th, 2006, 01:15 AM
Greg Buchholz
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


B. Williams wrote:
Quote:
I have written some code to accept input and place this input at the
beginning or end of a list, but I need assistance including a class so that
it will allow input of a phone number that is properly formatted. I'll post
my code below. Thanks in advance.
#include<iostream>
#include<list>
#include<iterator>
#include<boost/regex.hpp>
#include<cassert>

using namespace std;
class PhoneNumber
{ public:
PhoneNumber(const string a, const string e, const string s):
area_code(a), exchange(e), station(s){};
string area_code, exchange, station;
};

ostream &operator<<(ostream &o, const PhoneNumber &n)
{
return o << "(" << n.area_code << ") "
<< n.exchange << "-" << n.station;
}

// This should probably be something fancier
// http://en.wikipedia.org/wiki/North_A...Numbering_Plan
static const boost::regex
valid_ph("\\s*\\(?(\\d{3})\\)?\\s*[-.]?\\s*" // Area Code
"(\\d{3})\\s*[-.]?\\s*" // Exchange
"(\\d{4})\\s*"); // Station

void tests(void)
{
using namespace boost;
assert( regex_match("(800)555-1212" ,valid_ph));
assert( regex_match("800-555-1212 " ,valid_ph));
assert( regex_match("800.555.1212" ,valid_ph));
assert( regex_match("(800) 555 1212",valid_ph));
assert( regex_match("800 555 1212" ,valid_ph));
assert( regex_match("8005551212" ,valid_ph));
assert(not regex_match("800 555 12129" ,valid_ph));
assert(not regex_match(" 800 555 121" ,valid_ph));
assert(not regex_match("(foo) bar-quux",valid_ph));
}

int main(int argc, char* argv[])
{
string p;
list<PhoneNumberl;
boost::smatch m;

tests();
cout << "Enter Phone numbers (blank line to stop):\n";
while(true)
{
getline(cin,p);
if(not boost::regex_search(p,m,valid_ph)) break;
l.push_back(PhoneNumber (m[1].str(),m[2].str(),m[3].str()));
}

cout << "Phone numbers:\n";
copy(l.begin(),l.end(),ostream_iterator<PhoneNumbe r>(cout, "\n"));
return 0;
}

  #8  
Old December 6th, 2006, 02:55 PM
B. Williams
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


"BobR" <RemoveBadBobR@worldnet.att.netwrote in message
news:Hnodh.155258$Fi1.102919@bgtnsc05-news.ops.worldnet.att.net...
Quote:
>
B. Williams wrote in message ...
Quote:
>>
>>"Alf P. Steinbach" <alfps@start.nowrote in message ...
Quote:
>>Try to be a little more specific. Do you want someone to write the code
>>for you?
>>
>>I apologize for not being more specific. I know both of these work
>>independently, but I need help with incoporating the phone number class
>>into
>>the program. I couldn't figure out any better way to get the program to
>>accept phone numbers. I tried inputting the phone number as a string, but
>>the blank space ends the string. I guess I am asking for some assistance
>>on
>>writing the code, but I just need a kick start. This is the code to test
>>the
>>phone number class.
>>
>>#include <iostream>
>>using std::cout;
>>using std::cin;
>>using std::endl;
>>#include "PhoneNumber.h"
>
// suggestion:
istream& operator>>( istream &input, PhoneNumber &number ){
std::string line;
std::getline( input, line );
if( /* check something */ ){ /* do something */ } // like 'line.empty()'
>
if( '(' == line.at(0) && ')' == line.at(4) ){
number.areaCode = line.substr( 1, 3 ); // input area code
}
else{
number.areaCode = "GIGO";
}
number.exchange = line.substr( 6, 3 ); // input exchange
// etc.
>
// OR:
>
if( '(' == input.peek() ){
input.ignore();
}
if( input ){
input >number.areaCode;
if( ')' == number.areaCode.at(3) ){
number.areaCode.erase(3);
}
}
// etc.
>
return input; // enables cin >a >b >c;
} // end function operator>>
>
Quote:
>>
>>int main(){
> PhoneNumber phone;
> cout << "Enter phone number in the form (123) 456-7890:" << endl;
> cin >phone;
> cout << "The phone number entered was: ";
> cout << phone << endl;
> return 0;
>>} // end main.
>
--
Bob R
POVrookie
>
Bob,
What I am want to do is to incorporate the phone class into the list class
that I posted in my origional post. Will you assist me with that?


  #9  
Old December 6th, 2006, 07:29 PM
BobR
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


B. Williams wrote in message ...
Quote:
>
>Bob,
>What I am want to do is to incorporate the phone class into the list class
>that I posted in my origional post. Will you assist me with that?
I'll do what I can.

What do you mean by "incorporate the phone class into the list class"?

class Phone{};
class List{
Phone phoneNum;
};

--- or ---

class List{
Phone phoneNum;
class Phone{};
};

--- or ---

class List{
std::string phoneNum;
std::string areacode;
std::string prefix;
std::string numberpart;
public:
bool GetPhoneNumber(std::string &phone);
};

Your class List is templated. Will all the types it uses have a phone number?
"I can write to my friend 'int', because I have the address, but, I can't
find int's phone number! When I ask 'double' all I get is 1.234567890e+09!"
<G>

Is this what you want to do?:

List<PhoneNumberphonebook;

--
Bob R
POVrookie


  #10  
Old December 6th, 2006, 08:13 PM
B. Williams
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


"BobR" <RemoveBadBobR@worldnet.att.netwrote in message
news:f1Fdh.438469$QZ1.21693@bgtnsc04-news.ops.worldnet.att.net...
Quote:
>
B. Williams wrote in message ...
Quote:
>>
>>Bob,
>>What I am want to do is to incorporate the phone class into the list class
>>that I posted in my origional post. Will you assist me with that?
>
I'll do what I can.
>
What do you mean by "incorporate the phone class into the list class"?
>
class Phone{};
class List{
Phone phoneNum;
};
>
--- or ---
>
class List{
Phone phoneNum;
class Phone{};
};
>
--- or ---
>
class List{
std::string phoneNum;
std::string areacode;
std::string prefix;
std::string numberpart;
public:
bool GetPhoneNumber(std::string &phone);
};
>
Your class List is templated. Will all the types it uses have a phone
number?
"I can write to my friend 'int', because I have the address, but, I can't
find int's phone number! When I ask 'double' all I get is
1.234567890e+09!"
<G>
>
Is this what you want to do?:
>
List<PhoneNumberphonebook;
>
--
Bob R
POVrookie
>
Bob,
I don't really need the template because I just want to create a linked list
of phone numbers. I don't care about int' strings, etc... I probably went
about this the wrong way but I like to break things down because I'm fairly
new. That's why I have seperate code for both the linked list and the
phonenumber. I have gotten them to work seperately, now I just want to
phonenumber class to work so that I can create a linked list.


  #11  
Old December 6th, 2006, 08:33 PM
IR
Guest
 
Posts: n/a
Default Re: Assistance with linked lists

B. Williams wrote:
Quote:
I probably went about this the wrong way but I like to
break things down because I'm fairly new. That's why I have
seperate code for both the linked list and the phonenumber.
As a side note: even though you're "fairly new", you got the right
approach.

Every class (or template, for instance) must do only one thing, and do
it right. The smaller the pieces, the easier it is to get them right.

Remember:
- Keep it simple
- Small is beautiful

;-)


Cheers,
--
IR
  #12  
Old December 6th, 2006, 10:25 PM
BobR
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


B. Williams wrote in message ...
Quote:
>
>Bob,
>I don't really need the template because I just want to create a linked list
>of phone numbers. I don't care about int' strings, etc... I probably went
>about this the wrong way but I like to break things down because I'm fairly
>new. That's why I have seperate code for both the linked list and the
>phonenumber. I have gotten them to work seperately, now I just want to
>phonenumber class to work so that I can create a linked list.
Then you will probably want to do as Salt_Peter said in
alt.comp.lang.learn.c-c++:
Quote:
add the following to PhoneNumber:
a) a def ctor
b) a copy ctor
c) an assignment operator (not used, but required)
.....then test it:

std::vector<PhoneNumberphonebook;
// std::list<PhoneNumberphonebook;

.....then try:

List<PhoneNumberphonebook;


[ I just saw you posted code(or something big) on the other NG. I'll load it
and take a look. ]
--
Bob R
POVrookie


  #13  
Old December 7th, 2006, 01:35 AM
B Williams
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


"BobR" <RemoveBadBobR@worldnet.att.netwrote in message
news:FLHdh.439367$QZ1.124366@bgtnsc04-news.ops.worldnet.att.net...
Quote:
>
B. Williams wrote in message ...
Quote:
>>
>>Bob,
>>I don't really need the template because I just want to create a linked
>>list
>>of phone numbers. I don't care about int' strings, etc... I probably went
>>about this the wrong way but I like to break things down because I'm
>>fairly
>>new. That's why I have seperate code for both the linked list and the
>>phonenumber. I have gotten them to work seperately, now I just want to
>>phonenumber class to work so that I can create a linked list.
>
Then you will probably want to do as Salt_Peter said in
alt.comp.lang.learn.c-c++:
>
Quote:
>add the following to PhoneNumber:
>a) a def ctor
>b) a copy ctor
>c) an assignment operator (not used, but required)
>
....then test it:
>
std::vector<PhoneNumberphonebook;
// std::list<PhoneNumberphonebook;
>
....then try:
>
List<PhoneNumberphonebook;
>
>
[ I just saw you posted code(or something big) on the other NG. I'll load
it
and take a look. ]
--
Bob R
POVrookie
>
Bob,
Did you get a chance to look at the code I posted in the other NG?


  #14  
Old December 7th, 2006, 05:15 AM
BobR
Guest
 
Posts: n/a
Default Re: Assistance with linked lists


B Williams wrote in message ...
Quote:
>
>"BobR" wrote in message ...
Quote:
>[ I just saw you posted code(or something big) on the other NG. I'll load
>it and take a look. ]
>>
>Bob,
>Did you get a chance to look at the code I posted in the other NG?
Yup! Try the change (and test if() ). Report result.

--
Bob R
POVrookie


 

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are Off
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over network members.
Post your question now . . .
It's fast and it's free

Popular Articles