$args ) {
			new $class( $args[0], $args[1] );
		}
	}
//  ____________MAIN METHODS____________
	/**
	 * Constructor.
	 *
	 * @param string|bool $file (optional)
	 * @param object $options (optional) A scbOptions object.
	 *
	 * @return void
	 */
	public function __construct( $file = false, $options = null ) {
		if ( is_a( $options, 'scbOptions' ) ) {
			$this->options = $options;
		}
		$this->setup();
		$this->check_args();
		if ( isset( $this->option_name ) ) {
			add_action( 'admin_init', array( $this, 'option_init' ) );
		}
		add_action( 'admin_menu', array( $this, 'page_init' ), $this->args['admin_action_priority'] );
		if ( $file ) {
			$this->file = $file;
			$this->plugin_url = plugin_dir_url( $file );
			if ( $this->args['action_link'] ) {
				add_filter( 'plugin_action_links_' . plugin_basename( $file ), array( $this, '_action_link' ) );
			}
		}
	}
	/**
	 * This is where all the page args can be set.
	 *
	 * @return void
	 */
	protected function setup() { }
	/**
	 * Called when the page is loaded, but before any rendering.
	 * Useful for calling $screen->add_help_tab() etc.
	 *
	 * @return void
	 */
	public function page_loaded() {
		$this->form_handler();
	}
	/**
	 * This is where the css and js go.
	 * Both wp_enqueue_*() and inline code can be added.
	 *
	 * @return void
	 */
	public function page_head() { }
	/**
	 * This is where the contextual help goes.
	 *
	 * @return string
	 */
	protected function page_help() { }
	/**
	 * A generic page header.
	 *
	 * @return void
	 */
	protected function page_header() {
		echo "
\n";
		echo html( 'h2', $this->args['page_title'] );
	}
	/**
	 * This is where the page content goes.
	 *
	 * @return void
	 */
	abstract protected function page_content();
	/**
	 * A generic page footer.
	 *
	 * @return void
	 */
	protected function page_footer() {
		echo "
\n";
	}
	/**
	 * This is where the form data should be validated.
	 *
	 * @param array $new_data
	 * @param array $old_data
	 *
	 * @return array
	 */
	public function validate( $new_data, $old_data ) {
		return $new_data;
	}
	/**
	 * Manually handle option saving ( use Settings API instead ).
	 *
	 * @return bool
	 */
	protected function form_handler() {
		if ( empty( $_POST['submit'] ) && empty( $_POST['action'] ) ) {
			return false;
		}
		check_admin_referer( $this->nonce );
		if ( ! isset( $this->options ) ) {
			trigger_error( 'options handler not set', E_USER_WARNING );
			return false;
		}
		$new_data = wp_array_slice_assoc( $_POST, array_keys( $this->options->get_defaults() ) );
		$new_data = stripslashes_deep( $new_data );
		$new_data = $this->validate( $new_data, $this->options->get() );
		$this->options->set( $new_data );
		add_action( 'admin_notices', array( $this, 'admin_msg' ) );
		return true;
	}
	/**
	 * Manually generate a standard admin notice ( use Settings API instead ).
	 *
	 * @param string $msg (optional)
	 * @param string $class (optional)
	 *
	 * @return void
	 */
	public function admin_msg( $msg = '', $class = 'updated' ) {
		if ( empty( $msg ) ) {
			$msg = __( 'Settings saved.', $this->textdomain );
		}
		echo scb_admin_notice( $msg, $class );
	}
//  ____________UTILITIES____________
	/**
	 * Generates a form submit button.
	 *
	 * @param string|array $value (optional) Button text or array of arguments.
	 * @param string       $action (optional)
	 * @param string       $class (optional)
	 *
	 * @return string
	 */
	public function submit_button( $value = '', $action = 'submit', $class = 'button' ) {
		$args = is_array( $value ) ? $value : compact( 'value', 'action', 'class' );
		$args = wp_parse_args( $args, array(
			'value'  => null,
			'action' => $action,
			'class'  => $class,
		) );
		return get_submit_button( $args['value'], $args['class'], $args['action'] );
	}
	/**
	 * Mimics scbForms::form_wrap()
	 *
	 * $this->form_wrap( $content );  // generates a form with a default submit button
	 *
	 * $this->form_wrap( $content, false ); // generates a form with no submit button
	 *
	 *  // the second argument is sent to submit_button()
	 *  $this->form_wrap( $content, array(
	 *      'text' => 'Save changes',
	 *      'name' => 'action',
	 *  ) );
	 *
	 * @see scbForms::form_wrap()
	 *
	 * @param string               $content
	 * @param boolean|string|array $submit_button (optional)
	 *
	 * @return string
	 */
	public function form_wrap( $content, $submit_button = true ) {
		if ( is_array( $submit_button ) ) {
			$content .= $this->submit_button( $submit_button );
		} else if ( true === $submit_button ) {
			$content .= $this->submit_button();
		} else if ( false !== strpos( $submit_button, 'nonce );
	}
	/**
	 * Generates a table wrapped in a form.
	 *
	 * @param array         $rows
	 * @param array|boolean $formdata (optional)
	 *
	 * @return string
	 */
	public function form_table( $rows, $formdata = false ) {
		$output = '';
		foreach ( $rows as $row ) {
			$output .= $this->table_row( $row, $formdata );
		}
		$output = $this->form_table_wrap( $output );
		return $output;
	}
	/**
	 * Wraps the given content in a