public static void main(String[] args) throws IOException,
			URISyntaxException {

		// -----------------
		// 0.
		// INITIALIZES TIMER
		// -----------------

		// Initializes a Timer object
		//
		// This Timer begins timing once the user has given the authorization
		// code. Once all downloads are finished, it stops timing and will
		// display the elapsed processing time.

		Timer t = new Timer();

		// ------------------------------------------------------------------
		// 1.
		// SETS RUNTIME ARGUMENTS, INITIALIZES OUTPUTLOG, CHECKS REFRESH TOKEN
		// ------------------------------------------------------------------

		// Assigns runtime arguments to global variables.
		//
		// The user must specify 5 distinct runtime arguments to use the
		// program. The keyword, the minimum duration (in seconds), the maximum
		// duration (in seconds), quantity to download, and a file type (eg:
		// wav, mp3, ogg, etc..).
		//
		// NOTE: If the quantity exceeds the number of search results available
		// or the user inputs -1 for the quantity argument, all search results
		// will be downloaded.

		assignRuntimeArgs(args);
		if (flagRuntimeCommands) {
			return;
		}

		// Initializes an OutputLog object
		//
		// This OutputLog object exports the Sound objects' meta-data to a
		// keyword-specific JSON file. This makes it easy to read in the sound
		// files into whatever program requires them.
		try {
			out = new OutputLog(keyword + "_sounds.json");
		} catch (IOException e1) {
			e1.printStackTrace();
			flagJsonIndexFile = true;
		}

		// Checks for a previous refresh token file.
		//
		// Sets the refreshToken to the value stored in the refresh_token.json
		// file. This prevents the user from having to re-authenticate manually
		// by logging in to the Freesound API and obtaining a new authorization
		// code.
		refreshToken = getRefreshTokenFromFile();

		// ---------------------
		// 2.
		// OAUTH2 AUTHENTICATION
		// ---------------------

		if (refreshToken != null) {

			// Begin timer
			//
			// "Start" the Timer once the authorization code has been given.
			// More specifically, this just logs the current System time in
			// milliseconds.
			t.begin();

			// Exchanges refresh token for new access and refresh tokens.
			//
			// Using an HTTP POST request, the program exchanges the refresh
			// token for a new 24-hour access token and refresh token. The
			// program can now download .wav files from the Freesound API by
			// appending the access token to its queries.
			//
			// NOTE: If the stored refresh token has expired, the user must
			// manually obtain the authorization token.
			getAccessAndRefreshTokensFromAuthorizationCode(TokenType.REFRESH);
		}

		if (refreshToken == null || flagAccessToken) {

			System.out
					.println("\nERROR: The refresh token is either missing or expired.  Please log in again with your Freesound username and password.\n");

			// Opens api log in page in browser.
			//
			// User must log in with their Freesound account, then authorize
			// the program to run with their credentials. The user must copy
			// and paste the authorization code from the web browser and
			// into the program in the next step.

			launchLoginPage();
			if (flagLogIn) {
				return;
			}

			// Gets authorization code.
			//
			// This is a simple Scanner method to collect the user's
			// 10-minute authorization code from the previous step. It will
			// be used to get an access and refresh token to complete OAuth2
			// authentication and enable the program to download .wav files
			// from the Freesound API.

			getAuthorizationCodeFromUserInput();

			// Begin timer
			//
			// "Start" the Timer once the authorization code has been given.
			// More specifically, this just logs the current System time in
			// milliseconds.
			t.begin();

			// Exchanges authorization code for access and refresh tokens.
			//
			// Using an HTTP POST request, the program now exchanges the
			// authorization code for a 24-hour access token and refresh
			// token. The program can now download .wav files from the
			// Freesound API by appending the access token to its queries.

			getAccessAndRefreshTokensFromAuthorizationCode(TokenType.ACCESS);
			if (flagAccessToken) {
				return;
			}

		}

		System.out.println("\nACCESS TOKEN:\t\t" + accessToken);
		System.out.println("REFRESH TOKEN:\t\t" + refreshToken);

		// ------------------------------
		// 2.
		// QUERIES FREESOUND API (SEARCH)
		// ------------------------------

		// Searches for .wav files on Freesound.
		//
		// Using an HTTP GET request, the program uses the API key/client secret
		// to return a JSON search results page for that keyword and duration
		// threshold. This is then put into a List of Sound objects (global:
		// sounds) to handle exporting the .wav files to the keyword directory
		// and building the final JSON sounds list file.

		getSoundsList();
		if (flagSearch) {
			return;
		}

		// --------------------------------------
		// 3.
		// SAVES SOUND FILES TO KEYWORD DIRECTORY
		// --------------------------------------

		// Downloads the sounds from the Freesound API.
		//
		// Using the List of Sound objects, make the keyword directory then loop
		// over the Sound objects downloading the actual files from the
		// Freesound API and adding the JSON object to the index file. This
		// makes it easy to read in the sound files into whatever program
		// requires them.

		downloadSounds();
		if (flagDownload) {
			return;
		}

		System.out.println("\nFINISHED: " + numDownloaded
				+ " sound file(s) downloaded.");

		t.end();
		t.printFormattedExecutionTime();

	}