Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

[Tutorial] Quiz Game

AEDaveAEDave Posts: 135Registered Users
Quiz Game Tutorial & Walkthrough

Per a couple requests, I've gone ahead and put together a very simple quiz game. Here's what the game does:

- Loads a welcome screen, with a button to start the game.
- Loads questions with 4 potential answers.
- Provides a simple scoring mechanism; 50 points for right answers, 50 points for wrong ones.
- Allows players a few seconds to answer questions, and gives a brief break between questions.

So, that's the basics of it. The source files are attached below. Please note, this was coded in an afternoon, so there are some error messages that pop up, and some really bad code in the actual quiz itself! I'm going to update this thread once I rewrite the code...

Now I'm going to walk through some parts of the code. This is not the complete program, so to get the complete program please download the source code and run it. I'm just going to show off some of the highlights...

The header file:
#import <UIKit/UIKit.h>

@interface Quiz_GameViewController : UIViewController {
	IBOutlet	UILabel		*theQuestion;
	IBOutlet	UILabel		*theScore;
	IBOutlet	UILabel		*theLives;
	IBOutlet	UIButton	*answerOne;
	IBOutlet	UIButton	*answerTwo;
	IBOutlet	UIButton	*answerThree;
	IBOutlet	UIButton	*answerFour;
	NSInteger myScore;
	NSInteger myLives;
	NSInteger questionNumber;
	NSInteger rightAnswer;
	NSInteger time;
	NSArray *theQuiz;
	NSTimer *timer;
	BOOL questionLive;
	BOOL restartGame;
}

@property (retain, nonatomic) UILabel	*theQuestion;
@property (retain, nonatomic) UILabel	*theScore;
@property (retain, nonatomic) UILabel	*theLives;
@property (retain, nonatomic) UIButton	*answerOne;
@property (retain, nonatomic) UIButton	*answerTwo;
@property (retain, nonatomic) UIButton	*answerThree;
@property (retain, nonatomic) UIButton	*answerFour;
@property (retain, nonatomic) NSArray *theQuiz;
@property (retain, nonatomic) NSTimer *timer;

-(IBAction)buttonOne;
-(IBAction)buttonTwo;
-(IBAction)buttonThree;
-(IBAction)buttonFour;

-(void)checkAnswer;

-(void)askQuestion;

-(void)updateScore;

-(void)loadQuiz;

-(void)countDown;

@end

One thing worth noting is that I created an IBOutlet for the buttons; this provides the ability to change the text on them so the answers will be "clickable". I figure that's a pretty straightforward way to program it. As you can see in the header I've initialized some variables like booleans and integers, and most importantly an array that we'll use to actually load the quiz itself.

In IB, there are 3 main labels: The question area, the "score" and the timer counter box (which, I labeled "lives" inadvertently thinking I was going to have a lives counter... just run with it).

So, now in the .m file, here are some of the notable functions... (Please note, these are not in order as they appear in the code, so if you're looking at the source, you may have to scroll a little bit to find these things)

viewDidLoad:
- (void)viewDidLoad {
    [super viewDidLoad];
	questionLive = NO;
	restartGame = NO;
	theQuestion.text = @"Welcome to the Quiz Game! Think you're a pretty smart cookie, huh? Well, let's test your knowledge!";
	theScore.text = @"Score:0";
	theLives.text = @"";
	questionNumber = 0;
	myScore = 0;
	myLives = 0;
	[answerOne setTitle:@"Let's Play!" forState:UIControlStateNormal];
	[answerTwo setHidden:YES];
	[answerThree setHidden:YES];
	[answerFour setHidden:YES];
	[self loadQuiz];
}
This is just the initialization of the app, but it has some notable activities which might be worth noticing. First off, we've established some values for some of the variables that we'll be using in the game, including questionLive (a boolean), the questionNumber, myScore, etc. myLives will likely be killed in the next iteration of the game, since I'm not using that feature. You'll see how a lot of these get used later on. One of the handy pieces of code that I've used is the [... setTitle:] and [... setHidden:] features for the buttons. The buttons are UIButtons with IBOutlets attached to them in the Interface Builder, so we can manipulate them to be visible or hidden, or change the content of their text label. There are several states that buttons can be in when you set the title, but for convenience sake I only really care about UIControlStateNormal. Press the escape key while you're typing the statement, and a popup will appear with all the options...

The loadQuiz function is pretty straightforward, but it's important to note that this is a TERRIBLE way to program this. It SHOULD be nested arrays based on a dictionary, but for the sake of just getting this done I put it all in a flat NSArray. This is the thing that I'll be updating when I update this program, probably to access an independent file from resources like a plist or a txt file. Stay tuned for that update.

The "game" itself is in the function askQuestion:
-(void)askQuestion
{
	// Unhide all the answer buttons.
	[answerOne setHidden:NO];
	[answerTwo setHidden:NO];
	[answerThree setHidden:NO];
	[answerFour setHidden:NO];
	
	// Set the game to a "live" question (for timer purposes)
	questionLive = YES;
	
	// Set the time for the timer
	time = 8.0;
	
	// Go to the next question
	questionNumber = questionNumber + 1;
Here you can see some initialization features, such as un-hiding the buttons, setting the questionLive variable to "YES" so that the timer knows it's in a question (I'll explain that in a moment), setting the time for the timer (how long the player gets to answer the question, in this case 8 seconds), and updating the questionNumber to move to the next row.
	// THIS IS REALLY TERRIBLE CODE!!!
	// We get the question from the questionNumber * the row that we look up in the array.
	// This is absolutely horrible, just a placeholder until the right way.
	// I cannot even begin to describe how wrong this solution is.
	NSInteger row = 0;
	if(questionNumber == 1)
	{
		row = questionNumber - 1;
	}
	else
	{
		row = ((questionNumber - 1) * 6);
	}
	
	// Set the question string, and set the buttons the the answers
	NSString *selected = [theQuiz objectAtIndex:row];
	NSString *activeQuestion = [[NSString alloc] initWithFormat:@"Question: %@", selected];
	[answerOne setTitle:[theQuiz objectAtIndex:row+1] forState:UIControlStateNormal];
	[answerTwo setTitle:[theQuiz objectAtIndex:row+2] forState:UIControlStateNormal];
	[answerThree setTitle:[theQuiz objectAtIndex:row+3] forState:UIControlStateNormal];
	[answerFour setTitle:[theQuiz objectAtIndex:row+4] forState:UIControlStateNormal];
	rightAnswer = [[theQuiz objectAtIndex:row+5] intValue];
	
	// Set theQuestion label to the active question
	theQuestion.text = activeQuestion;
	
	// Start the timer for the countdown
	timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDown) userInfo:nil repeats:YES];
	
	[selected release];
	[activeQuestion release];

So all that stuff should be relatively self-explanatory if you just take a little while to look at it. Again, this is shameful programming (by skimming through a flat array to pull the question, answers, and right answer variables) but in short order it was what I came up with. Also, note the activation of the timer object, which uses the "countDown" function to warn the user of how much longer they have to answer the question.

Here's the code for -(IBAction)buttonOne function just so you see what's going on in there:
- (IBAction)buttonOne
{
	if(questionNumber == 0){
		// This means that we are at the startup-state
		// We need to make the other buttons visible, and start the game.
		[answerTwo setHidden:NO];
		[answerThree setHidden:NO];
		[answerFour setHidden:NO];
		[self askQuestion];
	}
	else
	{
		NSInteger theAnswerValue = 1;
		[self checkAnswer:(int)theAnswerValue];
		if(restartGame==YES)
		{
			// Create a restart game function.
		}
	}
}
Note that since button 1 is being used both as an answer button and as the "Let's play" game starter, we have to have a conditional statement in there to change it from the start button to a normal answer statement, which we accomplish by finding out if we're on question #0. If it's a normal question (in the 'else' portion of the conditional, covering all other situations), we set up a variable called theAnswerValue, which is the button number that they pressed, and then send that value to the function checkAnswer. This is creating a warning message in the process, so I need to check my syntax to code it right (it will run, but with warning errors - nothing severe though).

... continued ...
Post edited by AEDave on
«1345678

Replies

  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    ... continued from the previous post ...

    checkAnswer is pretty straightforward:
    -(void)checkAnswer:(int)theAnswerValue
    {
    	if(rightAnswer == theAnswerValue)
    	{
    		theQuestion.text = @"You're so money baby! Good work.";
    		myScore = myScore + 50;
    	}
    	else
    	{
    		theQuestion.text = @"Sorry weaksauce, you came up empty on that one!";
    		myScore = myScore - 50;
    	}
    	[self updateScore];
    }
    
    Notice rightAnswer is set in the askQuestion function, and is being compared to the theAnswerValue that was passed from the button action function (depending on what button was pressed, 1-4). If it is a match, they got it right, and they get a plithy response and 50 points. If it's not a match, they got it wrong, get shamed, and lose 50 points.

    Then we call updateScore function:
    -(void)updateScore
    {
    	// If the score is being updated, the question is not live
    	questionLive = NO;
    	
    	[timer invalidate];
    	
    	// Hide the answers from the previous question
    	[answerOne setHidden:YES];
    	[answerTwo setHidden:YES];
    	[answerThree setHidden:YES];
    	[answerFour setHidden:YES];
    	NSString *scoreUpdate = [[NSString alloc] initWithFormat:@"Score: %d", myScore];
    	theScore.text = scoreUpdate;
    	[scoreUpdate release];
    	
    	// END THE GAME.
    	NSInteger endOfQuiz = [theQuiz count];
    	if(((questionNumber) * 6) == endOfQuiz)
    	{
    		// Game is over.
    		if(myScore > 0)
    		{
    			NSString *finishingStatement = [[NSString alloc] initWithFormat:@"That's game!\nNice going \nYou scored %i!", myScore];
    			theQuestion.text = finishingStatement;
    			[finishingStatement release];
    		}
    		else
    		{
    			NSString *finishingStatement = [[NSString alloc] initWithFormat:@"That's game!\nWow. You're terrible! \nYou scored %i.", myScore];
    			theQuestion.text = finishingStatement;
    			[finishingStatement release];
    		}
    		theLives.text = @"";
    		
    		// Make button 1 appear as a reset game button
    		restartGame = YES;
    		[answerOne setHidden:NO];
    		[answerOne setTitle:@"Restart the game" forState:UIControlStateNormal];
    		
    	}
    	else
    	{
    	// Give a short rest between questions
    	time = 3.0;
    	
    	// Initialize the timer
    	timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDown) userInfo:nil repeats:YES];
    	}
    }
    

    So, that's essentially the rest of the heavy lifting the the app. The countDown function is worth a look, since that's where the timer runs through, but I think if you take a look at the source you should get what I'm doing in there.

    I welcome your questions about what I did, and I eagerly encourage any and all suggestions for improvements, enhancements, and coding short-cuts that I could have taken. Like I said, the main thing that I'm going to work on next is to change the method that the array is assembled (so we're using a series of multidimensional arrays to control questions, answers, etc); provide a mechanism to have variable question difficulty (and award variable points), and set it up so questions & answers will appear randomly. Also, I'd like to add a function to show the user the right answer when they get it wrong (or have that a setting that they can turn on or off).

    Anyways, thanks for reading! Hope this was helpful. :)

    Here's the link to the source: Quiz_Game.zip

    Dave
  • jin8kjin8k Posts: 10Registered Users
    edited March 2009
    wow!
    thanks Dave!!!

    I will look over your codes as soon as i am off from the work (european time)!!!
  • DrudooDrudoo Posts: 43Registered Users
    edited March 2009
    Is it possible to get the questions and answers from a .plist? then it would be easier to edit them :)
    My iPhone apps! <br />
    <a href="http://itunes.com/apps/ezytweet" target="_blank">ezyTweet</a> - $0.99<br />
    <a href="http://itunes.com/apps/izky" target="_blank">iZky</a> - $0.99
  • KalimbaKalimba ¿La Islas Hermosas?Posts: 2,181iPhone Dev SDK Supporter, Registered Users
    edited March 2009
    Drudoo wrote: »
    Is it possible to get the questions and answers from a .plist? then it would be easier to edit them :)
    That would absolutely be possible.
    <a href="http://bit.ly/gAmufK" target="_blank">icon-r-64.png</a> ~~ Word Flurry ~~ <a href="http://itunes.apple.com/us/app/word-flurry/id399660201?mt=8" target="_blank">App Store</a> / <a href="http://bit.ly/bJiK99
  • DrudooDrudoo Posts: 43Registered Users
    edited March 2009
    Anyone can make a tutorial of how to do this?
    My iPhone apps! <br />
    <a href="http://itunes.com/apps/ezytweet" target="_blank">ezyTweet</a> - $0.99<br />
    <a href="http://itunes.com/apps/izky" target="_blank">iZky</a> - $0.99
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    Yeah, that's the next piece I want to do. Like I said, the method I'm using isn't good at all! Haha. So yes, I'm going to update this file and provide some detail on how to use the plist and file-derived arrays.

    Dave
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    Well, short & simple, here is the redesign of the array declaration so that we can use a flat TXT file rather than writing the array in the code.
    -(void)loadQuiz
    {
    	NSBundle *bundle = [NSBundle mainBundle];
    	NSString *textFilePath = [bundle pathForResource:@"quizgame" ofType:@"txt"];
    	NSString *fileContents = [NSString stringWithContentsOfFile:textFilePath];
    	NSArray *quizArray = [[NSArray alloc] initWithArray:[fileContents componentsSeparatedByString:@"\n"]];
    	self.theQuiz = quizArray;
    	[quizArray release];
    }
    

    All this did was provide a quick way to create the array using a txt file called quizgame.txt moved in the 'Resources' group under "Groups & Files". Everything else in the code stays the same for now...

    To explain what's going on in this function now:
    1 - Create an instance of an NSBundle called bundle that we can use to access the file system. This way we don't need to actually write the exact path all the way to the root, this'll do it for us.
    2 - Create a string called textFilePath which uses the bundle to create a string with the location of the file we're trying to access. Note that you don't need to include the extension when describing the file, but you do need to set it in the 'ofType'.
    3 - Create a string called fileContents which contains the entire contents of the file. Worth noting, each line of the file will designate a new line in the array.
    4 - Populate the array quizArray with the contents of the fileContents, using the method componentsSeparatedByString of @"\n" which means every line break means it's a new element in the array.
    5 - Set theQuiz (our standing array of questions & answers) to quizArray and then...
    ... release quizArray

    So that's about it. The only real hiccup that I had in testing this is that the text file cannot have an ending blank line in it, as if you were going to write out more content. It'll record that as a new line in the array, and the game-ending code will fry (because it'll think there are more questions & answers). The formatting is still the same: 1st line is the question, lines 2-5 are answers, and line 6 is the right answer. So the text file might look like this...
    quizgame.txt:
    Who played the president on the TV show 'The West Wing'?
    Alan Alda
    Rob Lowe
    Martin Sheen
    Jack Bauer
    3
    What year did The Daily Show premier?
    1994
    1996
    1998
    2001
    2
    Who replaced Conan O'Brien on the Late Night show?
    Jimmy Kimmel
    Jimmy Tudeski
    Jimmy Dean
    Jimmy Fallon
    4
    

    So that's a quick upgrade to the code. Next, I'm trying to decide if I want to try to use a SQLite db or a plist file to actually break out these arrays in to something a little more meaningful (and add some new functionality in the process).

    Dave
  • DrudooDrudoo Posts: 43Registered Users
    edited March 2009
    Nice one :)
    But could you upload an example code ?
    My iPhone apps! <br />
    <a href="http://itunes.com/apps/ezytweet" target="_blank">ezyTweet</a> - $0.99<br />
    <a href="http://itunes.com/apps/izky" target="_blank">iZky</a> - $0.99
  • KalimbaKalimba ¿La Islas Hermosas?Posts: 2,181iPhone Dev SDK Supporter, Registered Users
    edited March 2009
    Drudoo wrote: »
    Nice one :)
    But could you upload an example code ?
    I'm sure he can, once he's polished up his silver platter. :rolleyes:
    <a href="http://bit.ly/gAmufK" target="_blank">icon-r-64.png</a> ~~ Word Flurry ~~ <a href="http://itunes.apple.com/us/app/word-flurry/id399660201?mt=8" target="_blank">App Store</a> / <a href="http://bit.ly/bJiK99
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    Kalimba wrote: »
    I'm sure he can, once he's polished up his silver platter. :rolleyes:

    Right? :p

    Dru, you should download the zip from the second post on this thread, change the function (void)loadQuiz to what I showed in the follow-up. Then create your own txt file of questions and answers, copy it to your project, and run the game. Should be literally that simple, since the main processes of the game haven't changed.

    Dave
  • jin8kjin8k Posts: 10Registered Users
    edited March 2009
    Hello Dave,

    I studied a bit your quiz tutorial and now trying to make something similar but I desperately need your teaching!

    I uploaded my files herehttp://www.jinweb.net/ferdi/iQQQ.zip, if u have time plz have a look and give me some directions how to move forward from here:o

    Your game has 4 answers as buttons, but what i tried to do is basically to have a simple interface where the answers are all embedded in the question, and there are 4 fixed answer buttons A,B,C,and D.

    Each time an answer is clicked (or Next button is clicked) the answer variable (ABCD) will be stored, and the next question will be displayed, and so on.
    At the end, a table should show the list of questions (1.2.3...), selected answer (user selected) and correct answer (red if wrong), with a total percentage grade.

    FIRST THING TO DO:
    I have created three string variables and each contains a question.
    now what i want to do is to have a loop function attached to button A,B,C, and D to store selected answer and move on to next question.

    Any idea how i can do this?

    iqqq.png
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    jin8k,

    There's a few things that come to mind. First off, using the UIToolbar is different from using buttons... I haven't really played around with them much, but I think with a little searching you can find out how to trigger the action based upon what button the user presses (it's different from how buttons are treated, but not by much).

    Regarding storing the information after you find out what someone pressed, I'd suggest glancing at this video tutorial: Welcome to the iPhone Development Central Website!

    It covers NSMutableArray which is a modifiable array you can use to dynamically store your answers. I'm assuming that what you're trying to do is get a user to the end of the quiz before telling them how many they got right or wrong. That just means you'll need to do something simple at the end like:
    i = 0
    rightanswers = 0
    for i++{
     if ((questionArray objectAtIndex:i) == (answerArray objectAtIndex:i)){
        rightanswers = rightanswers++;
      }
    }
    
  • jin8kjin8k Posts: 10Registered Users
    edited March 2009
    I figured out how to use the mutablearray and now restarted developing the quiz with intro view, main view and result view (all following switchview tutorial).

    My problem is very banal, when I switch from intro view (clicking Start button), the main view is shown, but the toolbar's position is not where I see from Interface builder.

    Intro View:
    izzz1.png

    Main View:
    izzz2.png

    What am I doing wrong? I also played with the size, position and autosizing, but no luck... also tried with other tools such as simple buttons (instead of toolbar), but the problem resists...

    The code is here: http://www.jinweb.net/ferdi/iZZZ.zip

    [SOLVED]: The size of the first view was : 480x300, and the second view was 460x320... don't know why, but I resized second view to 480x300 and resolved the problem :)
  • RobertD63RobertD63 Posts: 53Registered Users
    edited March 2009
    Okay I've edited this to a little more of my likings. I'm no developer at all, I've never coded in my life. But when ever at the end of the game taping the reset only freezes there. Any way to create a control to reset to the splash?
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    Robert, I kinda abandoned this project since it was just a quick tutorial. Never managed to hook up the reset button.

    If you do happen to cross that bridge, please post up your solution to help improve the overall tutorial!

    Cheers,

    Dave
  • RobertD63RobertD63 Posts: 53Registered Users
    edited March 2009
    Okay fair enough one last question though. How do I get it out of xCode? Like deploy it?
  • AEDaveAEDave Posts: 135Registered Users
    edited March 2009
    You need to set up a developer account, pay your $99 entry fee, and then you can load it on to a device.
  • RobertD63RobertD63 Posts: 53Registered Users
    edited March 2009
    AEDave wrote: »
    You need to set up a developer account, pay your $99 entry fee, and then you can load it on to a device.
    And that my friend is the end of my developing career. :p
  • scburns123scburns123 Posts: 35Registered Users
    edited April 2009
    I took a look at this tutorial thread and it has been very helpful indeed! Kudos to you kind sir!

    I am trying to do a similar quiz app and wanted to put images to questions. For instance if its a sports question I would put a sports picture, music question pic of guitar, etc.

    Could you perhaps give any guidance on this? I am thinking it would of course be another array with images loaded into it, however I am not sure how to tie the images to transition when the question was answered.

    Any sort of help would be much appreciated!!

    Thanks!
    Shawn
    <a href="itms://itunes.apple.com/us/app/hire-me/id314514956?mt=8" target="_blank">Hire Me!</a>
  • dunyduny Posts: 54Registered Users
    edited May 2009
    Anyone have the reset function to the quiz above, in this tutorial, that could share it.
  • magonicolasmagonicolas Posts: 32Registered Users
    edited May 2009
    Hello, This tutoril is very good! thx!
    I hace a question, how can I make Random Question Apear? I know how to create a random generator, but not to make it work with questions.
    Thx
  • M of IMAKM of IMAK Posts: 5New Users
    edited May 2009
    Hello, This tutoril is very good! thx!
    I hace a question, how can I make Random Question Apear? I know how to create a random generator, but not to make it work with questions.
    Thx

    Once you have 'random() % numberOfQuestions', just multiply by 6 (in this case of a flat array) and index into the array. You should also randomize the position of each answer to mix things up.

    I started out with random in 'That Ain't It! Trivia Game', but eventually moved to keeping track of which questions were displayed because using random was causing repeat questions more often than we liked.
  • magonicolasmagonicolas Posts: 32Registered Users
    edited May 2009
    M of IMAK wrote: »
    Once you have 'random() % numberOfQuestions', just multiply by 6 (in this case of a flat array) and index into the array. You should also randomize the position of each answer to mix things up.

    I started out with random in 'That Ain't It! Trivia Game', but eventually moved to keeping track of which questions were displayed because using random was causing repeat questions more often than we liked.

    Thx Dude! Finnaly ive got an answer.
    Can you upload a Sample Code? using the Quiz Game tutorial?

    How do I create random number of questions?

    Thx!
  • M of IMAKM of IMAK Posts: 5New Users
    edited May 2009
    Thx Dude! Finnaly ive got an answer.
    Can you upload a Sample Code? using the Quiz Game tutorial?

    How do I create random number of questions?

    Thx!

    Sorry, I don't have any sample code to upload. What do you mean by 'create a random number of questions?' I would probably be more helpful in answering questions about the That Ain't It! trivia app I wrote. You can check out the YouTube video (search IMAKcreations) and I'll be happy to answer any questions about it. It took quite a bit longer to write than 1 day, but I learned a lot.
  • RobertD63RobertD63 Posts: 53Registered Users
    edited May 2009
    Okay reading through my old posts I feel bad cause I was kinda rude/true noob.

    But thats not what I wanted to ask. I created a new button called endButton and set it to be the button to start the game and end it. I did this because I set my buttons to have a different layout and the start and end buttons look bad. So my problem is when ever i swich the button from this:
    [answerOne setTitle:@"Let's Play!" forState:UIControlStateNormal];
    
    to:
    [endButton setTitle:@"Let's Play!" forState:UIControlStateNormal];
    
    and then hide answerOne the endButton does nothing. But when I unhide answerOne it still loads the quiz. What am I missing here? So it looks like this:
    - (void)viewDidLoad {
        [super viewDidLoad];
    	questionLive = NO;
    	restartGame = NO;
    	theQuestion.text = @"Welcome to the Quiz Game! Think you're a pretty smart cookie, huh? Well, let's test your knowledge!";
    	theScore.text = @"Score:0";
    	theLives.text = @"";
    	questionNumber = 0;
    	myScore = 0;
    	myLives = 0;
    	[endButton setTitle:@"Let's Play!" forState:UIControlStateNormal];
    	[answerOne setHidden:YES];
    	[answerTwo setHidden:YES];
    	[answerThree setHidden:YES];
    	[answerFour setHidden:YES];
    	[self loadQuiz];
    

    I've done all the connections and code i've needed to do that I know of. I hooked the button up in IB.
«1345678
Sign In or Register to comment.