whole_func_string: function( args ) {
  	if ( ! isObject( args ) ) {
  		args = {};
  	}
  
  	defaultsDeep( args, defaults );
  
  	verifyArguments( args );
  
  	this.config = args;
  
  	if ( args.debouncedRefresh === true ) {
  		this.refresh = debounce( this.refresh.bind( this ), inputDebounceDelay );
  	}
  	this._pureRefresh = throttle( this._pureRefresh.bind( this ), this.config.typeDelay );
  
  	this.callbacks = this.config.callbacks;
  	this.i18n = this.constructI18n( this.config.translations );
  
  	this.initializeAssessors( args );
  
  	this.pluggable = new Pluggable( this );
  
  	this.getData();
  
  	this.defaultOutputElement = this.getDefaultOutputElement( args );
  
  	if ( this.defaultOutputElement !== "" ) {
  		this.showLoadingDialog();
  	}
  
  	if ( isValidSnippetPreview( args.snippetPreview ) ) {
  		this.snippetPreview = args.snippetPreview;
  
  		/* Hack to make sure the snippet preview always has a reference to this App. This way we solve the circular
  		dependency issue. In the future this should be solved by the snippet preview not having a reference to the
  		app.*/
  		if ( this.snippetPreview.refObj !== this ) {
  			this.snippetPreview.refObj = this;
  			this.snippetPreview._i18n = this.i18n;
  		}
  	} else if ( args.hasSnippetPreview ) {
  		this.snippetPreview = createDefaultSnippetPreview.call( this );
  	}
  
  	this._assessorOptions = {
  		useCornerStone: false,
  		useKeywordDistribution: false,
  	};
  
  	this.initSnippetPreview();
  	this.initAssessorPresenters();
  }
func_code_string: function( args ) {
  	if ( ! isObject( args ) ) {
  		args = {};
  	}
  
  	defaultsDeep( args, defaults );
  
  	verifyArguments( args );
  
  	this.config = args;
  
  	if ( args.debouncedRefresh === true ) {
  		this.refresh = debounce( this.refresh.bind( this ), inputDebounceDelay );
  	}
  	this._pureRefresh = throttle( this._pureRefresh.bind( this ), this.config.typeDelay );
  
  	this.callbacks = this.config.callbacks;
  	this.i18n = this.constructI18n( this.config.translations );
  
  	this.initializeAssessors( args );
  
  	this.pluggable = new Pluggable( this );
  
  	this.getData();
  
  	this.defaultOutputElement = this.getDefaultOutputElement( args );
  
  	if ( this.defaultOutputElement !== "" ) {
  		this.showLoadingDialog();
  	}
  
  	if ( isValidSnippetPreview( args.snippetPreview ) ) {
  		this.snippetPreview = args.snippetPreview;
  
  		/* Hack to make sure the snippet preview always has a reference to this App. This way we solve the circular
  		dependency issue. In the future this should be solved by the snippet preview not having a reference to the
  		app.*/
  		if ( this.snippetPreview.refObj !== this ) {
  			this.snippetPreview.refObj = this;
  			this.snippetPreview._i18n = this.i18n;
  		}
  	} else if ( args.hasSnippetPreview ) {
  		this.snippetPreview = createDefaultSnippetPreview.call( this );
  	}
  
  	this._assessorOptions = {
  		useCornerStone: false,
  		useKeywordDistribution: false,
  	};
  
  	this.initSnippetPreview();
  	this.initAssessorPresenters();
  }
func_documentation_string: @callback YoastSEO.App~updatedKeywordsResults
  
  @param {Object[]} result The updated keywords analysis results.
  @param {number} result[].score The SEO score.
  @param {string} result[].rating String representation of the SEO score.
  @param {string} result[].text Textual explanation of the score.
  @param {number} overallContentScore The overall keywords SEO score.
   
  Loader for the analyzer, loads the eventbinder and the elementdefiner
  
  @param {Object} args The arguments passed to the loader.
  @param {Object} args.translations Jed compatible translations.
  @param {Object} args.targets Targets to retrieve or set on.
  @param {String} args.targets.snippet ID for the snippet preview element.
  @param {String} args.targets.output ID for the element to put the output of the analyzer in.
  @param {int} args.typeDelay Number of milliseconds to wait between typing to refresh the analyzer output.
  @param {boolean} args.dynamicDelay   Whether to enable dynamic delay, will ignore type delay if the analyzer takes a long time.
  Applicable on slow devices.
  @param {int} args.maxTypeDelay The maximum amount of type delay even if dynamic delay is on.
  @param {int} args.typeDelayStep The amount with which to increase the typeDelay on each step when dynamic delay is enabled.
  @param {Object} args.callbacks The callbacks that the app requires.
  @param {Object} args.assessor The Assessor to use instead of the default assessor.
  @param {YoastSEO.App~getData} args.callbacks.getData Called to retrieve input data
  @param {YoastSEO.App~getAnalyzerInput} args.callbacks.getAnalyzerInput Called to retrieve input for the analyzer.
  @param {YoastSEO.App~bindElementEvents} args.callbacks.bindElementEvents Called to bind events to the DOM elements.
  @param {YoastSEO.App~updateSnippetValues} args.callbacks.updateSnippetValues Called when the snippet values need to be updated.
  @param {YoastSEO.App~saveScores} args.callbacks.saveScores Called when the score has been determined by the analyzer.
  @param {YoastSEO.App~saveContentScore} args.callback.saveContentScore Called when the content score has been
  determined by the assessor.
  @param {YoastSEO.App~updatedContentResults} args.callbacks.updatedContentResults Called when the score has been determined
  by the analyzer.
  @param {YoastSEO.App~updatedKeywordsResults} args.callback.updatedKeywordsResults Called when the content score has been
  determined by the assessor.
  @param {Function} args.callbacks.saveSnippetData Function called when the snippet data is changed.
  @param {Function} args.marker The marker to use to apply the list of marks retrieved from an assessment.
  
  @param {SnippetPreview} args.snippetPreview The SnippetPreview object to be used.
  @param {boolean} [args.debouncedRefresh] Whether or not to debounce the
  refresh function. Defaults to true.
  
  @constructor