text:
<?php
/*
 * oauth_client.php
 *
 * @(#) $Id: oauth_client.php,v 1.46 2013/01/10 10:11:33 mlemos Exp $
 *
 */

/*
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
<class>

	<package>net.manuellemos.oauth</package>

	<version>@(#) $Id: oauth_client.php,v 1.46 2013/01/10 10:11:33 mlemos Exp $</version>
	<copyright>Copyright © (C) Manuel Lemos 2012</copyright>
	<title>OAuth client</title>
	<author>Manuel Lemos</author>
	<authoraddress>mlemos-at-acm.org</authoraddress>

	<documentation>
		<idiom>en</idiom>
		<purpose>This class serves two main purposes:<paragraphbreak />
			1) Implement the OAuth protocol to retrieve a token from a server to
			authorize the access to an API on behalf of the current
			user.<paragraphbreak />
			2) Perform calls to a Web services API using a token previously
			obtained using this class or a token provided some other way by the
			Web services provider.</purpose>
		<usage>Regardless of your purposes, you always need to start calling
			the class <functionlink>Initialize</functionlink> function after
			initializing setup variables. After you are done with the class,
			always call the <functionlink>Finalize</functionlink> function at
			the end.<paragraphbreak />
			This class supports either OAuth protocol versions 1.0, 1.0a and
			2.0. It abstracts the differences between these protocol versions,
			so the class usage is the same independently of the OAuth
			version of the server.<paragraphbreak />
			The class also provides built-in support to several popular OAuth
			servers, so you do not have to manually configure all the details to
			access those servers. Just set the
			<variablelink>server</variablelink> variable to configure the class
			to access one of the built-in supported servers.<paragraphbreak />
			If you need to access one type of server that is not yet directly
			supported by the class, you need to configure it explicitly setting
			the variables: <variablelink>oauth_version</variablelink>,
			<variablelink>url_parameters</variablelink>,
			<variablelink>authorization_header</variablelink>,
			<variablelink>request_token_url</variablelink>,
			<variablelink>dialog_url</variablelink>,
			<variablelink>append_state_to_redirect_uri</variablelink> and
			<variablelink>access_token_url</variablelink>.<paragraphbreak />
			Before proceeding to the actual OAuth authorization process, you
			need to have registered your application with the OAuth server. The
			registration provides you values to set the variables
			<variablelink>client_id</variablelink> and
			<variablelink>client_secret</variablelink>.<paragraphbreak />
			You also need to set the variables
			<variablelink>redirect_uri</variablelink> and
			<variablelink>scope</variablelink> before calling the
			<functionlink>Process</functionlink> function to make the class
			perform the necessary interactions with the OAuth
			server.<paragraphbreak />
			The OAuth protocol involves multiple steps that include redirection
			to the OAuth server. There it asks permission to the current user to
			grant your application access to APIs on his/her behalf. When there
			is a redirection, the class will set the
			<variablelink>exit</variablelink> variable to
			<booleanvalue>1</booleanvalue>. Then your script should exit
			immediately without outputting anything.<paragraphbreak />
			When the OAuth access token is successfully obtained, the following
			variables are set by the class with the obtained values:
			<variablelink>access_token</variablelink>,
			<variablelink>access_token_secret</variablelink>,
			<variablelink>access_token_expiry</variablelink>,
			<variablelink>access_token_type</variablelink>. You may want to
			store these values to use them later when calling the server
			APIs.<paragraphbreak />
			If there was a problem during OAuth authorization process, check the
			variable <variablelink>authorization_error</variablelink> to
			determine the reason.<paragraphbreak />
			Once you get the access token, you can call the server APIs using
			the <functionlink>CallAPI</functionlink> function. Check the
			<variablelink>access_token_error</variablelink> variable to
			determine if there was an error when trying to to call the
			API.<paragraphbreak />
			If for some reason the user has revoked the access to your
			application, you need to ask the user to authorize your application
			again. First you may need to call the function
			<functionlink>ResetAccessToken</functionlink> to reset the value of
			the access token that may be cached in session variables.</usage>
	</documentation>

{/metadocument}
*/

class oauth_client_class
{
/*
{metadocument}
	<variable>
		<name>error</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Store the message that is returned when an error
				occurs.</purpose>
			<usage>Check this variable to understand what happened when a call to
				any of the class functions has failed.<paragraphbreak />
				This class uses cumulative error handling. This means that if one
				class functions that may fail is called and this variable was
				already set to an error message due to a failure in a previous call
				to the same or other function, the function will also fail and does
				not do anything.<paragraphbreak />
				This allows programs using this class to safely call several
				functions that may fail and only check the failure condition after
				the last function call.<paragraphbreak />
				Just set this variable to an empty string to clear the error
				condition.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $error = '';

/*
{metadocument}
	<variable>
		<name>debug</name>
		<type>BOOLEAN</type>
		<value>0</value>
		<documentation>
			<purpose>Control whether debug output is enabled</purpose>
			<usage>Set this variable to <booleanvalue>1</booleanvalue> if you
				need to check what is going on during calls to the class. When
				enabled, the debug output goes either to the variable
				<variablelink>debug_output</variablelink> and the PHP error log.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $debug = false;

/*
{metadocument}
	<variable>
		<name>debug_http</name>
		<type>BOOLEAN</type>
		<value>0</value>
		<documentation>
			<purpose>Control whether the dialog with the remote Web server
				should also be logged.</purpose>
			<usage>Set this variable to <booleanvalue>1</booleanvalue> if you
				want to inspect the data exchange with the OAuth server.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $debug_http = false;

/*
{metadocument}
	<variable>
		<name>exit</name>
		<type>BOOLEAN</type>
		<value>0</value>
		<documentation>
			<purpose>Determine if the current script should be exited.</purpose>
			<usage>Check this variable after calling the
				<functionlink>Process</functionlink> function and exit your script
				immediately if the variable is set to
				<booleanvalue>1</booleanvalue>.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $exit = false;

/*
{metadocument}
	<variable>
		<name>debug_output</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Capture the debug output generated by the class</purpose>
			<usage>Inspect this variable if you need to see what happened during
				the class function calls.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $debug_output = '';

/*
{metadocument}
	<variable>
		<name>debug_prefix</name>
		<type>STRING</type>
		<value>OAuth client: </value>
		<documentation>
			<purpose>Mark the lines of the debug output to identify actions
				performed by this class.</purpose>
			<usage>Change this variable if you prefer the debug output lines to
				be prefixed with a different text.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $debug_prefix = 'OAuth client: ';

/*
{metadocument}
	<variable>
		<name>server</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Identify the type of OAuth server to access.</purpose>
			<usage>The class provides built-in support to several types of OAuth
				servers. This means that the class can automatically initialize
				several configuration variables just by setting this server
				variable.<paragraphbreak />
				Currently it supports the following servers:
				<stringvalue>Bitbucket</stringvalue>,
				<stringvalue>Dropbox</stringvalue>,
				<stringvalue>Facebook</stringvalue>,
				<stringvalue>Fitbit</stringvalue>,
				<stringvalue>Flickr</stringvalue>,
				<stringvalue>Foursquare</stringvalue>,
				<stringvalue>github</stringvalue>,
				<stringvalue>Google</stringvalue>,
				<stringvalue>Instagram</stringvalue>,
				<stringvalue>LinkedIn</stringvalue>,
				<stringvalue>Microsoft</stringvalue>,
				<stringvalue>Scoop.it</stringvalue>,
				<stringvalue>Tumblr</stringvalue>,
				<stringvalue>Twitter</stringvalue> and
				<stringvalue>Yahoo</stringvalue>. Please contact the author if you
				would like to ask to add built-in support for other types of OAuth
				servers.<paragraphbreak />
				If you want to access other types of OAuth servers that are not
				yet supported, set this variable to an empty string and configure
				other variables with values specific to those servers.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $server = '';

/*
{metadocument}
	<variable>
		<name>request_token_url</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>URL of the OAuth server to request the initial token for
				OAuth 1.0 and 1.0a servers.</purpose>
			<usage>Set this variable to the OAuth request token URL when you are
				not accessing one of the built-in supported OAuth
				servers.<paragraphbreak />
				For OAuth 1.0 and 1.0a servers, the request token URL can have
				certain marks that will act as template placeholders which will be
				replaced with given values before requesting the authorization
				token. Currently it supports the following placeholder
				marks:<paragraphbreak />
				{SCOPE} - scope of the requested permissions to the granted by the
				OAuth server with the user permissions</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $request_token_url = '';

/*
{metadocument}
	<variable>
		<name>dialog_url</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>URL of the OAuth server to redirect the browser so the user
				can grant access to your application.</purpose>
			<usage>Set this variable to the OAuth request token URL when you are
				not accessing one of the built-in supported OAuth servers.<paragraphbreak />
				For OAuth 2.0 servers, the dialog URL can have certain marks that
				will act as template placeholders which will be replaced with
				values defined before redirecting the users browser. Currently it
				supports the following placeholder marks:<paragraphbreak />
				{REDIRECT_URI} - URL to redirect when returning from the OAuth
				server authorization page<paragraphbreak />
				{CLIENT_ID} - client application identifier registered at the
				server<paragraphbreak />
				{SCOPE} - scope of the requested permissions to the granted by the
				OAuth server with the user permissions<paragraphbreak />
				{STATE} - identifier of the OAuth session state</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $dialog_url = '';

/*
{metadocument}
	<variable>
		<name>append_state_to_redirect_uri</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Pass the OAuth session state in a variable with a different
				name to work around implementation bugs of certain OAuth
				servers</purpose>
			<usage>Set this variable  when you are not accessing one of the
				built-in supported OAuth servers if the OAuth server has a bug
				that makes it not pass back the OAuth state identifier in a
				request variable named state.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $append_state_to_redirect_uri = '';

/*
{metadocument}
	<variable>
		<name>access_token_url</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>OAuth server URL that will return the access token
				URL.</purpose>
			<usage>Set this variable to the OAuth access token URL when you are
				not accessing one of the built-in supported OAuth servers.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token_url = '';

/*
{metadocument}
	<variable>
		<name>oauth_version</name>
		<type>STRING</type>
		<value>2.0</value>
		<documentation>
			<purpose>Version of the protocol version supported by the OAuth
				server.</purpose>
			<usage>Set this variable to the OAuth server protocol version when
				you are not accessing one of the built-in supported OAuth
				servers.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $oauth_version = '2.0';

/*
{metadocument}
	<variable>
		<name>url_parameters</name>
		<type>BOOLEAN</type>
		<value>0</value>
		<documentation>
			<purpose>Determine if the API call parameters should be moved to the
				call URL.</purpose>
			<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
				API you need to call requires that the call parameters always be
				passed via the API URL.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $url_parameters = false;

/*
{metadocument}
	<variable>
		<name>authorization_header</name>
		<type>BOOLEAN</type>
		<value>1</value>
		<documentation>
			<purpose>Determine if the OAuth parameters should be passed via HTTP
				Authorization request header.</purpose>
			<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
				OAuth server requires that the OAuth parameters be passed using
				the HTTP Authorization instead of the request URI parameters.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $authorization_header = true;

/*
{metadocument}
	<variable>
		<name>redirect_uri</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>URL of the current script page that is calling this
				class</purpose>
			<usage>Set this variable to the current script page URL before
				proceeding the the OAuth authorization process.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $redirect_uri = '';

/*
{metadocument}
	<variable>
		<name>client_id</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Identifier of your application registered with the OAuth
				server</purpose>
			<usage>Set this variable to the application identifier that is
				provided by the OAuth server when you register the
				application.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $client_id = '';

/*
{metadocument}
	<variable>
		<name>client_secret</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Secret value assigned to your application when it is
				registered with the OAuth server.</purpose>
			<usage>Set this variable to the application secret that is provided
				by the OAuth server when you register the application.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $client_secret = '';

/*
{metadocument}
	<variable>
		<name>scope</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Permissions that your application needs to call the OAuth
				server APIs</purpose>
			<usage>Check the documentation of the APIs that your application
				needs to call to set this variable with the identifiers of the
				permissions that the user needs to grant to your application.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $scope = '';

/*
{metadocument}
	<variable>
		<name>access_token</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Access token obtained from the OAuth server</purpose>
			<usage>Check this variable to get the obtained access token upon
				successful OAuth authorization.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token = '';

/*
{metadocument}
	<variable>
		<name>access_token_secret</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Access token secret obtained from the OAuth server</purpose>
			<usage>If the OAuth protocol version is 1.0 or 1.0a, check this
				variable to get the obtained access token secret upon successful
				OAuth authorization.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token_secret = '';

/*
{metadocument}
	<variable>
		<name>access_token_expiry</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Timestamp of the expiry of the access token obtained from
				the OAuth server.</purpose>
			<usage>Check this variable to get the obtained access token expiry
				time upon successful OAuth authorization. If this variable is
				empty, that means no expiry time was set.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token_expiry = '';

/*
{metadocument}
	<variable>
		<name>access_token_type</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Type of access token obtained from the OAuth server.</purpose>
			<usage>Check this variable to get the obtained access token type
				upon successful OAuth authorization.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token_type = '';

/*
{metadocument}
	<variable>
		<name>access_token_error</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Error message returned when a call to the API fails.</purpose>
			<usage>Check this variable to determine if there was an error while
				calling the Web services API when using the
				<functionlink>CallAPI</functionlink> function.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $access_token_error = '';

/*
{metadocument}
	<variable>
		<name>authorization_error</name>
		<type>STRING</type>
		<value></value>
		<documentation>
			<purpose>Error message returned when it was not possible to obtain
				an OAuth access token</purpose>
			<usage>Check this variable to determine if there was an error while
				trying to obtain the OAuth access token.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $authorization_error = '';

/*
{metadocument}
	<variable>
		<name>response_status</name>
		<type>INTEGER</type>
		<value>0</value>
		<documentation>
			<purpose>HTTP response status returned by the server when calling an
				API</purpose>
			<usage>Check this variable after calling the
				<functionlink>CallAPI</functionlink> function if the API calls and you
				need to process the error depending the response status.
				<integervalue>200</integervalue> means no error.
				<integervalue>0</integervalue> means the server response was not
				retrieved.</usage>
		</documentation>
	</variable>
{/metadocument}
*/
	var $response_status = 0;

	var $oauth_user_agent = 'PHP-OAuth-API (http://www.phpclasses.org/oauth-api $Revision: 1.46 $)';
	var $session_started = false;

	Function SetError($error)
	{
		$this->error = $error;
		if($this->debug)
			$this->OutputDebug('Error: '.$error);
		return(false);
	}

	Function SetPHPError($error, &$php_error_message)
	{
		if(IsSet($php_error_message)
		&& strlen($php_error_message))
			$error.=": ".$php_error_message;
		return($this->SetError($error));
	}

	Function OutputDebug($message)
	{
		if($this->debug)
		{
			$message = $this->debug_prefix.$message;
			$this->debug_output .= $message."\n";;
			error_log($message);
            cw_log_add('mslive', array('oauth client message'=>$message));
		}
		return(true);
	}

	Function GetRequestTokenURL(&$request_token_url)
	{
		$request_token_url = $this->request_token_url;
		return(true);
	}

	Function GetDialogURL(&$redirect_url)
	{
		$redirect_url = $this->dialog_url;
		return(true);
	}

	Function GetAccessTokenURL(&$access_token_url)
	{
		$access_token_url = $this->access_token_url;
		return(true);
	}

	Function GetStoredState(&$state)
	{
		if(IsSet($_SESSION['OAUTH_STATE']))
			$state = $_SESSION['OAUTH_STATE'];
		else
			$state = $_SESSION['OAUTH_STATE'] = time().'-'.substr(md5(rand().time()), 0, 6);
		return(true);
	}

	Function GetRequestState(&$state)
	{
		$check = (strlen($this->append_state_to_redirect_uri) ? $this->append_state_to_redirect_uri : 'state');
		$state = (IsSet($_GET[$check]) ? $_GET[$check] : null);
cw_log_add('mslive', array('state'=>$state));
		return(true);
	}

	Function GetRequestCode(&$code)
	{
		$code = (IsSet($_GET['code']) ? $_GET['code'] : null);
cw_log_add('mslive', array('code'=>$code));
		return(true);
	}

	Function GetRequestError(&$error)
	{
		$error = (IsSet($_GET['error']) ? $_GET['error'] : null);
		return(true);
	}

	Function GetRequestDenied(&$denied)
	{
		$denied = (IsSet($_GET['denied']) ? $_GET['denied'] : null);
		return(true);
	}

	Function GetRequestToken(&$token, &$verifier)
	{
		$token = (IsSet($_GET['oauth_token']) ? $_GET['oauth_token'] : null);
		$verifier = (IsSet($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : null);
		return(true);
	}

	Function GetRedirectURI(&$redirect_uri)
	{
		if(strlen($this->redirect_uri))
			$redirect_uri = $this->redirect_uri;
		else
			$redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
		return true;
	}

/*
{metadocument}
	<function>
		<name>StoreAccessToken</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Store the values of the access token when it is succefully
				retrieved from the OAuth server.</purpose>
			<usage>This function is meant to be only be called from inside the
				class. By default it stores access tokens in a session variable
				named <stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
				Actual implementations should create a sub-class and override this
				function to make the access token values be stored in other types
				of containers, like for instance databases.</usage>
			<returnvalue>This function should return
				<booleanvalue>1</booleanvalue> if the access token was stored
				successfully.</returnvalue>
		</documentation>
		<argument>
			<name>access_token</name>
			<type>HASH</type>
			<documentation>
				<purpose>Associative array with properties of the access token.
					The array may have set the following
					properties:<paragraphbreak />
					<stringvalue>value</stringvalue>: string value of the access
						token<paragraphbreak />
					<stringvalue>authorized</stringvalue>: boolean value that
						determines if the access token was obtained
						successfully<paragraphbreak />
					<stringvalue>expiry</stringvalue>: (optional) timestamp in ISO
						format relative to UTC time zone of the access token expiry
						time<paragraphbreak />
					<stringvalue>type</stringvalue>: (optional) type of OAuth token
						that may determine how it should be used when sending API call
						requests.</purpose>
			</documentation>
		</argument>
		<do>
{/metadocument}
*/
	Function StoreAccessToken($access_token)
	{
cw_log_add('mslive', array('stored access_token'=>$access_token));
		$_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url] = $access_token;
		return true;
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>GetAccessToken</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Retrieve the OAuth access token if it was already
				previously stored by the
				<functionlink>StoreAccessToken</functionlink> function.</purpose>
			<usage>This function is meant to be only be called from inside the
				class. By default it retrieves access tokens stored in a session
				variable named
				<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
				Actual implementations should create a sub-class and override this
				function to retrieve the access token values from other types of
				containers, like for instance databases.</usage>
			<returnvalue>This function should return
				<booleanvalue>1</booleanvalue> if the access token was retrieved
				successfully.</returnvalue>
		</documentation>
		<argument>
			<name>access_token</name>
			<type>STRING</type>
			<out />
			<documentation>
				<purpose>Return the properties of the access token in an
					associative array. If the access token was not yet stored, it
					returns an empty array. Otherwise, the properties it may return
					are the same that may be passed to the
					<functionlink>StoreAccessToken</functionlink>.</purpose>
			</documentation>
		</argument>
		<do>
{/metadocument}
*/
	Function GetAccessToken(&$access_token)
	{
		if(!$this->session_started
		&& !session_start())
			return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message));
		$this->session_started = true;
		if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]))
			$access_token = $_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url];
		else
			$access_token = array();
cw_log_add('mslive', array('get access_token'=>$access_token));
		return true;
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>ResetAccessToken</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Reset the access token to a state back when the user has
				not yet authorized the access to the OAuth server API.</purpose>
			<usage>Call this function if for some reason the token to access
				the API was revoked and you need to ask the user to authorize
				the access again.<paragraphbreak />
				By default the class stores and retrieves access tokens in a
				session variable named
				<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
				This function must be called when the user is accessing your site
				pages, so it can reset the information stored in session variables
				that cache the state of a previously retrieved access
				token.<paragraphbreak />
				Actual implementations should create a sub-class and override this
				function to reset the access token state when it is stored in
				other types of containers, like for instance databases.</usage>
			<returnvalue>This function should return
				<booleanvalue>1</booleanvalue> if the access token was resetted
				successfully.</returnvalue>
		</documentation>
		<do>
{/metadocument}
*/
	Function ResetAccessToken()
	{
		if($this->debug)
			$this->OutputDebug('Resetting the access token status for OAuth server located at '.$this->access_token_url);
		if(!$this->session_started
		&& !session_start())
			return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message));
		$this->session_started = true;
		if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]))
			Unset($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]);
		return true;
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

	Function Encode($value)
	{
		return(is_array($value) ? $this->EncodeArray($value) : str_replace('%7E', '~', str_replace('+',' ', RawURLEncode($value))));
	}

	Function EncodeArray($array)
	{
		foreach($array as $key => $value)
			$array[$key] = $this->Encode($value);
		return $array;
	}

	Function HMAC($function, $data, $key)
	{
		switch($function)
		{
			case 'sha1':
				$pack = 'H40';
				break;
			default:
				if($this->debug)
					$this->OutputDebug($function.' is not a supported an HMAC hash type');
				return('');
		}
		if(strlen($key) > 64)
			$key = pack($pack, $function($key));
		if(strlen($key) < 64)
			$key = str_pad($key, 64, "\0");
		return(pack($pack, $function((str_repeat("\x5c", 64) ^ $key).pack($pack, $function((str_repeat("\x36", 64) ^ $key).$data)))));
	}

	Function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response)
	{
		$this->response_status = 0;
		$http = new http_class;
		$http->debug = ($this->debug && $this->debug_http);
		$http->log_debug = true;
		$http->sasl_authenticate = 0;
		$http->user_agent = $this->oauth_user_agent;
		if($this->debug)
			$this->OutputDebug('Accessing the '.$options['Resource'].' at '.$url);
		$arguments = array();
		$method = strtoupper($method);
		$authorization = '';
		$type = (IsSet($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : 'application/x-www-form-urlencoded');
		if(IsSet($oauth))
		{
			$values = array(
				'oauth_consumer_key'=>$this->client_id,
				'oauth_nonce'=>md5(uniqid(rand(), true)),
				'oauth_signature_method'=>'HMAC-SHA1',
				'oauth_timestamp'=>time(),
				'oauth_version'=>'1.0',
			);
			if($this->url_parameters
			&& $type === 'application/x-www-form-urlencoded'
			&& count($parameters))
			{
				$first = (strpos($url, '?') === false);
				foreach($parameters as $parameter => $value)
					$url .= ($first ? '?' : '&').UrlEncode($parameter).'='.UrlEncode($value);
				$parameters = array();
			}
			$value_parameters = ($type !== 'application/x-www-form-urlencoded' ? array() : $parameters);
			$values = array_merge($values, $oauth, $value_parameters);
			$uri = strtok($url, '?');
			$sign = $method.'&'.$this->Encode($uri).'&';
			$first = true;
			$sign_values = $values;
			$u = parse_url($url);
			if(IsSet($u['query']))
			{
				parse_str($u['query'], $q);
				foreach($q as $parameter => $value)
					$sign_values[$parameter] = $value;
			}
			KSort($sign_values);
			foreach($sign_values as $parameter => $value)
			{
				$sign .= $this->Encode(($first ? '' : '&').$parameter.'='.$this->Encode($value));
				$first = false;
			}
			$key = $this->Encode($this->client_secret).'&'.$this->Encode($this->access_token_secret);
			$values['oauth_signature'] = base64_encode($this->HMAC('sha1', $sign, $key));
			if($this->authorization_header)
			{
				$authorization = 'OAuth';
				$first = true;
				foreach($values as $parameter => $value)
				{
					$authorization .= ($first ? ' ' : ',').$parameter.'="'.$this->Encode($value).'"';
					$first = false;
				}
			}
			else
			{
				if($method === 'GET')
				{
					$first = (strcspn($url, '?') == strlen($url));
					foreach($values as $parameter => $value)
					{
						$url .= ($first ? '?' : '&').$parameter.'='.$this->Encode($value);
						$first = false;
					}
					$post_values = array();
				}
				else
					$post_values = $values;
			}
		}
		if(strlen($error = $http->GetRequestArguments($url, $arguments)))
			return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error));
		if(strlen($error = $http->Open($arguments)))
			return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error));
		$arguments['RequestMethod'] = $method;
		switch($type)
		{
			case 'application/x-www-form-urlencoded':
				if(IsSet($options['RequestBody']))
					return($this->SetError('the request body is defined automatically from the parameters'));
				$arguments['PostValues'] = $parameters;
				break;
			case 'application/json':
				$arguments['Headers']['Content-Type'] = $options['RequestContentType'];
				if(!IsSet($options['RequestBody']))
				{
					$arguments['Body'] = json_encode($parameters);
					break;
				}
			default:
				if(!IsSet($options['RequestBody']))
					return($this->SetError('it was not specified the body value of the of the API call request'));
				$arguments['Headers']['Content-Type'] = $options['RequestContentType'];
				$arguments['Body'] = $options['RequestBody'];
				break;
		}
		$arguments['Headers']['Accept'] = (IsSet($options['Accept']) ? $options['Accept'] : '*/*');
		if(strlen($authorization))
			$arguments['Headers']['Authorization'] = $authorization;
		if(strlen($error = $http->SendRequest($arguments))
		|| strlen($error = $http->ReadReplyHeaders($headers)))
		{
			$http->Close();
			return($this->SetError('it was not possible to retrieve the '.$options['Resource'].': '.$error));
		}
		$error = $http->ReadWholeReplyBody($data);
		$http->Close();
		if(strlen($error))
		{
			return($this->SetError('it was not possible to access the '.$options['Resource'].': '.$error));
		}
		$this->response_status = intval($http->response_status);
		$content_type = (IsSet($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified');
		switch($content_type)
		{
			case 'text/javascript':
			case 'application/json':
				if(!function_exists('json_decode'))
					return($this->SetError('the JSON extension is not available in this PHP setup'));
				$object = json_decode($data);
				switch(GetType($object))
				{
					case 'object':
						if(!IsSet($options['ConvertObjects'])
						|| !$options['ConvertObjects'])
							$response = $object;
						else
						{
							$response = array();
							foreach($object as $property => $value)
								$response[$property] = $value;
						}
						break;
					case 'array':
						$response = $object;
						break;
					default:
						if(!IsSet($object))
							return($this->SetError('it was not returned a valid JSON definition of the '.$options['Resource'].' values'));
						$response = $object;
						break;
				}
				break;
			case 'application/x-www-form-urlencoded':
			case 'text/plain':
			case 'text/html':
				parse_str($data, $response);
				break;
			default:
				$response = $data;
				break;
		}
		if($this->response_status >= 200
		&& $this->response_status < 300)
			$this->access_token_error = '';
		else
		{
			$this->access_token_error = 'it was not possible to access the '.$options['Resource'].': it was returned an unexpected response status '.$http->response_status.' Response: '.$data;
			if($this->debug)
				$this->OutputDebug('Could not retrieve the OAuth access. Error: '.$this->access_token_error);
			if(IsSet($options['FailOnAccessError'])
			&& $options['FailOnAccessError'])
			{
				$this->error = $this->access_token_error;
				return false;
			}
		}
		return true;
	}

/*
{metadocument}
	<function>
		<name>CallAPI</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Send a HTTP request to the Web services API using a
				previously obtained authorization token via OAuth.</purpose>
			<usage>This function can be used to call an API after having
				previously obtained an access token through the OAuth protocol
				using the <functionlink>Process</functionlink> function, or by
				directly setting the variables
				<variablelink>access_token</variablelink>, as well as
				<variablelink>access_token_secret</variablelink> in case of using
				OAuth 1.0 or 1.0a services.</usage>
			<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
				the call was done successfully.</returnvalue>
		</documentation>
		<argument>
			<name>url</name>
			<type>STRING</type>
			<documentation>
				<purpose>URL of the API where the HTTP request will be sent.</purpose>
			</documentation>
		</argument>
		<argument>
			<name>method</name>
			<type>STRING</type>
			<documentation>
				<purpose>HTTP method that will be used to send the request. It can
				be <stringvalue>GET</stringvalue>,
				<stringvalue>POST</stringvalue>,
				<stringvalue>DELETE</stringvalue>, <stringvalue>PUT</stringvalue>,
				etc..</purpose>
			</documentation>
		</argument>
		<argument>
			<name>parameters</name>
			<type>HASH</type>
			<documentation>
				<purpose>Associative array with the names and values of the API
					call request parameters.</purpose>
			</documentation>
		</argument>
		<argument>
			<name>options</name>
			<type>HASH</type>
			<documentation>
				<purpose>Associative array with additional options to configure
					the request. Currently it supports the following
					options:<paragraphbreak />
					<stringvalue>Resource</stringvalue>: string with a label that
						will be used in the error messages and debug log entries to
						identify what operation the request is performing. The default
						value is <stringvalue>API call</stringvalue>.<paragraphbreak />
					<stringvalue>ConvertObjects</stringvalue>: boolean option that
						determines if objects should be converted into arrays when the
						response is returned in JSON format. The default value is
						<booleanvalue>0</booleanvalue>.<paragraphbreak />
					<stringvalue>FailOnAccessError</stringvalue>: boolean option
						that determines if this functions should fail when the server
						response status is not between 200 and 299. The default value
						is <booleanvalue>0</booleanvalue>.<paragraphbreak />
					<stringvalue>Accept</stringvalue>: content type value of the
						Accept HTTP header to be sent in the API call HTTP request.
						Some APIs require that a certain value be sent to specify
						which version of the API is being called. The default value is
						<stringvalue>*/*</stringvalue>.<paragraphbreak />
					<stringvalue>RequestContentType</stringvalue>: content type that
						should be used to send the request values. It can be either
						<stringvalue>application/x-www-form-urlencoded</stringvalue>
						for sending values like from Web forms, or
						<stringvalue>application/json</stringvalue> for sending the
						values encoded in JSON format. Other types are accepted if the
						<stringvalue>RequestBody</stringvalue> option is specified.
						The default value is
						<stringvalue>application/x-www-form-urlencoded</stringvalue>.<paragraphbreak />
					<stringvalue>RequestBody</stringvalue>: request body data of a
						custom type. The <stringvalue>RequestContentType</stringvalue>
						option must be specified, so the
						<stringvalue>RequestBody</stringvalue> option is considered.</purpose>
			</documentation>
		</argument>
		<argument>
			<name>response</name>
			<type>STRING</type>
			<out />
			<documentation>
				<purpose>Return the value of the API response. If the value is
					JSON encoded, this function will decode it and return the value
					converted to respective types. If the value is form encoded,
					this function will decode the response and return it as an
					array. Otherwise, the class will return the value as a
					string.</purpose>
			</documentation>
		</argument>
		<do>
{/metadocument}
*/
	Function CallAPI($url, $method, $parameters, $options, &$response)
	{
		if(!IsSet($options['Resource']))
			$options['Resource'] = 'API call';
		if(!IsSet($options['ConvertObjects']))
			$options['ConvertObjects'] = false;
		switch(intval($this->oauth_version))
		{
			case 1:
				$oauth = array(
					'oauth_token'=>$this->access_token
				);
				break;

			case 2:
				$oauth = null;
				$url .= (strcspn($url, '?') < strlen($url) ? '&' : '?').'access_token='.UrlEncode($this->access_token);
				break;

			default:
				return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol'));
		}
		return($this->SendAPIRequest($url, $method, $parameters, $oauth, $options, $response));
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>Initialize</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Initialize the class variables and internal state. It must
				be called before calling other class functions.</purpose>
			<usage>Set the <variablelink>server</variablelink> variable before
				calling this function to let it initialize the class variables to
				work with the specified server type. Alternatively, you can set
				other class variables manually to make it work with servers that
				are not yet built-in supported.</usage>
			<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
				it was able to successfully initialize the class for the specified
				server type.</returnvalue>
		</documentation>
		<do>
{/metadocument}
*/
	Function Initialize()
	{
		switch($this->server)
		{
			case '';
				break;

			case 'Bitbucket':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token';
				$this->dialog_url = 'https://bitbucket.org/!api/1.0/oauth/authenticate';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = true;
				break;

			case 'Dropbox':
				$this->oauth_version = '1.0';
				$this->request_token_url = 'https://api.dropbox.com/1/oauth/request_token';
				$this->dialog_url = 'https://www.dropbox.com/1/oauth/authorize';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://api.dropbox.com/1/oauth/access_token';
				$this->authorization_header = false;
				$this->url_parameters = false;
				break;

			case 'Facebook':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url = 'https://www.facebook.com/dialog/oauth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://graph.facebook.com/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Fitbit':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'http://api.fitbit.com/oauth/request_token';
				$this->dialog_url = 'http://api.fitbit.com/oauth/authorize';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'http://api.fitbit.com/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Flickr':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'http://www.flickr.com/services/oauth/request_token';
				$this->dialog_url = 'http://www.flickr.com/services/oauth/authorize';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'http://www.flickr.com/services/oauth/access_token';
				$this->authorization_header = false;
				$this->url_parameters = false;
				break;

			case 'Foursquare':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url = 'https://foursquare.com/oauth2/authorize?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://foursquare.com/oauth2/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'github':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url = 'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://github.com/login/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Google':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://accounts.google.com/o/oauth2/token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Instagram':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url ='https://api.instagram.com/oauth/authorize/?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://api.instagram.com/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'LinkedIn':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken?scope={SCOPE}';
				$this->dialog_url = 'https://api.linkedin.com/uas/oauth/authenticate';
				$this->access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
				$this->append_state_to_redirect_uri = '';
				$this->authorization_header = true;
				$this->url_parameters = true;
				break;

			case 'Microsoft':
				$this->oauth_version = '2.0';
				$this->request_token_url = '';
				$this->dialog_url = 'https://login.live.com/oauth20_authorize.srf?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://login.live.com/oauth20_token.srf';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Scoop.it':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'https://www.scoop.it/oauth/request';
				$this->dialog_url = 'https://www.scoop.it/oauth/authorize';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://www.scoop.it/oauth/access';
				$this->authorization_header = false;
				$this->url_parameters = false;
				break;

			case 'Tumblr':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'http://www.tumblr.com/oauth/request_token';
				$this->dialog_url = 'http://www.tumblr.com/oauth/authorize';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'http://www.tumblr.com/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = false;
				break;

			case 'Twitter':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'https://api.twitter.com/oauth/request_token';
				$this->dialog_url = 'https://api.twitter.com/oauth/authenticate';
				$this->append_state_to_redirect_uri = '';
				$this->access_token_url = 'https://api.twitter.com/oauth/access_token';
				$this->authorization_header = true;
				$this->url_parameters = true;
				break;

			case 'Yahoo':
				$this->oauth_version = '1.0a';
				$this->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token';
				$this->dialog_url = 'https://api.login.yahoo.com/oauth/v2/request_auth';
				$this->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token';
				$this->append_state_to_redirect_uri = '';
				$this->authorization_header = false;
				$this->url_parameters = false;
				break;

			default:
				return($this->SetError($this->server.' is not yet a supported type of OAuth server. Please contact the author Manuel Lemos <mlemos@acm.org> to request adding built-in support to this type of OAuth server.'));
		}
		return(true);
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>Process</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Process the OAuth protocol interaction with the OAuth
				server.</purpose>
			<usage>Call this function when you need to retrieve the OAuth access
				token. Check the <variablelink>access_token</variablelink> to
				determine if the access token was obtained successfully.</usage>
			<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
				the OAuth protocol was processed without errors.</returnvalue>
		</documentation>
		<do>
{/metadocument}
*/
	Function Process()
	{
		switch(intval($this->oauth_version))
		{
			case 1:
				$one_a = ($this->oauth_version === '1.0a');
				if($this->debug)
					$this->OutputDebug('Checking the OAuth token authorization state');
				if(!$this->GetAccessToken($access_token))
					return false;
				if(IsSet($access_token['authorized'])
				&& IsSet($access_token['value']))
				{
					$expired = (IsSet($access_token['expiry']) && strcmp($access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0);
					if(!$access_token['authorized']
					|| $expired)
					{
						if($this->debug)
						{
							if($expired)
								$this->OutputDebug('The OAuth token expired on '.$access_token['expiry'].'UTC');
							else
								$this->OutputDebug('The OAuth token is not yet authorized');
							$this->OutputDebug('Checking the OAuth token and verifier');
						}
						if(!$this->GetRequestToken($token, $verifier))
							return false;
						if(!IsSet($token)
						|| ($one_a
						&& !IsSet($verifier)))
						{
							if(!$this->GetRequestDenied($denied))
								return false;
							if(IsSet($denied)
							&& $denied === $access_token['value'])
							{
								if($this->debug)
									$this->OutputDebug('The authorization request was denied');
								$this->authorization_error = 'the request was denied';
								return true;
							}
							else
							{
								if($this->debug)
									$this->OutputDebug('Reset the OAuth token state because token and verifier are not both set');
								$access_token = array();
							}
						}
						elseif($token !== $access_token['value'])
						{
							if($this->debug)
								$this->OutputDebug('Reset the OAuth token state because token does not match what as previously retrieved');
							$access_token = array();
						}
						else
						{
							if(!$this->GetAccessTokenURL($url))
								return false;
							$oauth = array(
								'oauth_token'=>$token,
							);
							if($one_a)
								$oauth['oauth_verifier'] = $verifier;
							$this->access_token_secret = $access_token['secret'];
							if(!$this->SendAPIRequest($url, 'GET', array(), $oauth, array('Resource'=>'OAuth access token'), $response))
								return false;
							if(strlen($this->access_token_error))
							{
								$this->authorization_error = $this->access_token_error;
								return true;
							}
							if(!IsSet($response['oauth_token'])
							|| !IsSet($response['oauth_token_secret']))
							{
								$this->authorization_error= 'it was not returned the access token and secret';
								return true;
							}
							$access_token = array(
								'value'=>$response['oauth_token'],
								'secret'=>$response['oauth_token_secret'],
								'authorized'=>true
							);
							if(IsSet($response['oauth_expires_in']))
							{
								$expires = $response['oauth_expires_in'];
								if(strval($expires) !== strval(intval($expires))
								|| $expires <= 0)
									return($this->SetError('OAuth server did not return a supported type of access token expiry time'));
								$this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires);
								if($this->debug)
									$this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC');
								$access_token['expiry'] = $this->access_token_expiry;
							}
							else
								$this->access_token_expiry = '';

							if(!$this->StoreAccessToken($access_token))
								return false;
							if($this->debug)
								$this->OutputDebug('The OAuth token was authorized');
						}
					}
					elseif($this->debug)
						$this->OutputDebug('The OAuth token was already authorized');
					if(IsSet($access_token['authorized'])
					&& $access_token['authorized'])
					{
						$this->access_token = $access_token['value'];
						$this->access_token_secret = $access_token['secret'];
						return true;
					}
				}
				else
				{
					if($this->debug)
						$this->OutputDebug('The OAuth access token is not set');
					$access_token = array();
				}
				if(!IsSet($access_token['authorized']))
				{
					if($this->debug)
						$this->OutputDebug('Requesting the unauthorized OAuth token');
					if(!$this->GetRequestTokenURL($url))
						return false;
					$url = str_replace('{SCOPE}', UrlEncode($this->scope), $url);
					if(!$this->GetRedirectURI($redirect_uri))
						return false;
					$oauth = array(
						'oauth_callback'=>$redirect_uri,
					);
					if(!$this->SendAPIRequest($url, 'GET', array(), $oauth, array('Resource'=>'OAuth request token'), $response))
						return false;
					if(strlen($this->access_token_error))
					{
						$this->authorization_error = $this->access_token_error;
						return true;
					}
					if(!IsSet($response['oauth_token'])
					|| !IsSet($response['oauth_token_secret']))
					{
						$this->authorization_error = 'it was not returned the requested token';
						return true;
					}
					$access_token = array(
						'value'=>$response['oauth_token'],
						'secret'=>$response['oauth_token_secret'],
						'authorized'=>false
					);
					if(!$this->StoreAccessToken($access_token))
						return false;
				}
				if(!$this->GetDialogURL($url))
					return false;
				$url .= '?oauth_token='.$access_token['value'];
				if(!$one_a)
				{
					if(!$this->GetRedirectURI($redirect_uri))
						return false;
					$url .= '&oauth_callback='.UrlEncode($redirect_uri);
				}
				if($this->debug)
					$this->OutputDebug('Redirecting to OAuth authorize page '.$url);
				Header('HTTP/1.0 302 OAuth Redirection');
				Header('Location: '.$url);
				$this->exit = true;
				return true;

			case 2:
				if($this->debug)
					$this->OutputDebug('Checking if OAuth access token was already retrieved from '.$this->access_token_url);
				if(!$this->GetAccessToken($access_token))
					return false;
				if(IsSet($access_token['value']))
				{
					if(IsSet($access_token['expiry'])
					&& strcmp($this->access_token_expiry = $access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) < 0)
					{
						if($this->debug)
							$this->OutputDebug('The OAuth access token expired in '.$this->access_token_expiry);
					}
					else
					{
						$this->access_token = $access_token['value'];
						if(IsSet($access_token['type']))
							$this->access_token_type = $access_token['type'];
						if($this->debug)
							$this->OutputDebug('The OAuth access token '.$this->access_token.' is valid');
						if(strlen($this->access_token_type)
						&& $this->debug)
							$this->OutputDebug('The OAuth access token is of type '.$this->access_token_type);
						return true;
					}
				}
				if($this->debug)
					$this->OutputDebug('Checking the authentication state in URI '.$_SERVER['REQUEST_URI']);
				if(!$this->GetStoredState($stored_state))
					return false;
				if(strlen($stored_state) == 0)
					return($this->SetError('it was not set the OAuth state'));
				if(!$this->GetRequestState($state))
					return false;
				if($state === $stored_state)
				{
					if($this->debug)
						$this->OutputDebug('Checking the authentication code');
					if(!$this->GetRequestCode($code))
						return false;
					if(strlen($code) == 0)
					{
						if(!$this->GetRequestError($this->authorization_error))
							return false;
						if(IsSet($this->authorization_error))
						{
							if($this->debug)
								$this->OutputDebug('Authorization failed with error code '.$this->authorization_error);
							switch($this->authorization_error)
							{
								case 'invalid_request':
								case 'unauthorized_client':
								case 'access_denied':
								case 'unsupported_response_type':
								case 'invalid_scope':
								case 'server_error':
								case 'temporarily_unavailable':
								case 'user_denied':
									return true;
								default:
									return($this->SetError('it was returned an unknown OAuth error code'));
							}
						}
						return($this->SetError('it was not returned the OAuth dialog code'));
					}
					if(!$this->GetAccessTokenURL($url))
						return false;
					if(!$this->GetRedirectURI($redirect_uri))
						return false;
					$values = array(
						'code'=>$code,
						'client_id'=>$this->client_id,
						'client_secret'=>$this->client_secret,
						'redirect_uri'=>$redirect_uri,
						'grant_type'=>'authorization_code'
					);
					if(!$this->SendAPIRequest($url, 'POST', $values, null, array('Resource'=>'OAuth access token', 'ConvertObjects'=>true), $response))
						return false;
					if(strlen($this->access_token_error))
					{
						$this->authorization_error = $this->access_token_error;
						return true;
					}
					if(!IsSet($response['access_token']))
					{
						if(IsSet($response['error']))
						{
							$this->authorization_error = 'it was not possible to retrieve the access token: it was returned the error: '.$response['error'];
							return true;
						}
						return($this->SetError('OAuth server did not return the access token'));
					}
					$access_token = array(
						'value'=>$this->access_token = $response['access_token'],
						'authorized'=>true
					);
					if($this->debug)
						$this->OutputDebug('Access token: '.$this->access_token);
					if(IsSet($response['expires'])
					|| IsSet($response['expires_in']))
					{
						$expires = (IsSet($response['expires']) ? $response['expires'] : $response['expires_in']);
						if(strval($expires) !== strval(intval($expires))
						|| $expires <= 0)
							return($this->SetError('OAuth server did not return a supported type of access token expiry time'));
						$this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires);
						if($this->debug)
							$this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC');
						$access_token['expiry'] = $this->access_token_expiry;
					}
					else
						$this->access_token_expiry = '';
					if(IsSet($response['token_type']))
					{
						$this->access_token_type = $response['token_type'];
						if($this->debug)
							$this->OutputDebug('Access token type: '.$this->access_token_type);
						$access_token['type'] = $this->access_token_type;
					}
					else
						$this->access_token_type = '';
					if(!$this->StoreAccessToken($access_token))
						return false;
				}
				else
				{
					if(!$this->GetDialogURL($url))
						return false;
					if(strlen($url) == 0)
						return($this->SetError('it was not set the OAuth dialog URL'));
					if(!$this->GetRedirectURI($redirect_uri))
						return false;
					if(strlen($this->append_state_to_redirect_uri))
						$redirect_uri .= (strpos($redirect_uri, '?') === false ? '?' : '&').$this->append_state_to_redirect_uri.'='.$stored_state;
					$url = str_replace(
						'{REDIRECT_URI}', UrlEncode($redirect_uri), str_replace(
						'{CLIENT_ID}', UrlEncode($this->client_id), str_replace(
						'{SCOPE}', UrlEncode($this->scope), str_replace(
						'{STATE}', UrlEncode($stored_state),
						$url))));
					if($this->debug)
						$this->OutputDebug('Redirecting to OAuth Dialog '.$url);
					Header('HTTP/1.0 302 OAuth Redirection');
					Header('Location: '.$url);
					$this->exit = true;
				}
				break;

			default:
				return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol'));
		}
		return(true);
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>Finalize</name>
		<type>BOOLEAN</type>
		<documentation>
			<purpose>Cleanup any resources that may have been used during the
				OAuth protocol processing or execution of API calls.</purpose>
			<usage>Always call this function as the last step after calling the
				functions <functionlink>Process</functionlink> or
				<functionlink>CallAPI</functionlink>.</usage>
			<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
				the function cleaned up any resources successfully.</returnvalue>
		</documentation>
		<argument>
			<name>success</name>
			<type>BOOLEAN</type>
			<documentation>
				<purpose>Pass the last success state returned by the class or any
					external code processing the class function results.</purpose>
			</documentation>
		</argument>
		<do>
{/metadocument}
*/
	Function Finalize($success)
	{
		return($success);
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

/*
{metadocument}
	<function>
		<name>Output</name>
		<type>VOID</type>
		<documentation>
			<purpose>Display the results of the OAuth protocol processing.</purpose>
			<usage>Only call this function if you are debugging the OAuth
				authorization process and you need to view what was its
				results.</usage>
		</documentation>
		<do>
{/metadocument}
*/
	Function Output()
	{
		if(strlen($this->authorization_error)
		|| strlen($this->access_token_error)
		|| strlen($this->access_token))
		{
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>OAuth client result</title>
</head>
<body>
<h1>OAuth client result</h1>
<?php
			if(strlen($this->authorization_error))
			{
?>
<p>It was not possible to authorize the application.<?php
				if($this->debug)
				{
?>
<br>Authorization error: <?php echo HtmlSpecialChars($this->authorization_error);
				}
?></p>
<?php
			}
			elseif(strlen($this->access_token_error))
			{
?>
<p>It was not possible to use the application access token.
<?php
				if($this->debug)
				{
?>
<br>Error: <?php echo HtmlSpecialChars($this->access_token_error);
				}
?></p>
<?php
			}
			elseif(strlen($this->access_token))
			{
?>
<p>The application authorization was obtained successfully.
<?php
				if($this->debug)
				{
?>
<br>Access token: <?php echo HtmlSpecialChars($this->access_token);
					if(IsSet($this->access_token_secret))
					{
?>
<br>Access token secret: <?php echo HtmlSpecialChars($this->access_token_secret);
					}
				}
?></p>
<?php
				if(strlen($this->access_token_expiry))
				{
?>
<p>Access token expiry: <?php echo $this->access_token_expiry; ?> UTC</p>
<?php
				}
			}
?>
</body>
</html>
<?php
		}
	}
/*
{metadocument}
		</do>
	</function>
{/metadocument}
*/

};

/*

{metadocument}
</class>
{/metadocument}

*/

?>


text:
About Adoption Funding
Adopting Families
Adoption & Foster Resources
Learn About TBRI
TBRI in the Classroom
Simulcasts/Conferences
Organizational Training
Matching Grant Update
by Matt Borst | Jan 4, 2023 | Oasis, Uncategorized
Many of you know that we were the recipient of a $500,000 grant in 2022. We received $250,000 of that grant upfront and the remaining $250,000 is a matching grant. This means that we have to raise $250,000 in order to get the second $250,000 of the grant. As of 12/31/2022, we have raised $157,696 of this matching grant so we have a total of $92,304 left to raise. We would love to raise this remaining balance by June 1, 2023. If you would like to help us reach this goal, you can make a donation by clicking here.
Below are a few pictures of the progress that is being made at Oasis.
Connect Parenting
Empowered To Connect
Goal Reached
Karyn Purvis
Marshall Family
Orphan Care Interview
TBRI
2022 – What A Year!
Oasis Update
HALO Program! (Coming Soon)
Groundbreaking!!
Archives Select Month January 2023 December 2022 November 2022 September 2022 August 2022 April 2022 December 2020 December 2019 December 2018 October 2018 September 2018 August 2018 July 2018 May 2018 April 2018 March 2018 February 2018 December 2017 November 2017 October 2017 September 2017 July 2017 June 2017 May 2017 April 2017 February 2017 January 2017 December 2016 November 2016 September 2016 August 2016 July 2016 June 2016 May 2016 April 2016 March 2016 February 2016 January 2016 December 2015 November 2015 October 2015 August 2015 July 2015 June 2015 May 2015 April 2015 March 2015 February 2015 January 2015 October 2014 September 2014 July 2014 June 2014 May 2014 April 2014 March 2014 February 2014 January 2014 December 2013 November 2013 October 2013 September 2013 August 2013 May 2013 April 2013 March 2013 February 2013 January 2013 December 2012 November 2012 October 2012 September 2012 August 2012 July 2012 June 2012 January 2012 December 2011
Categories Select Category Adoption Connect Parenting Connected Parenting Empowered To Connect Family Spotlight Fatherhood Foster Care Goal Reached Karyn Purvis Marshall Family Oasis Orphan Care Interview Positive Stories Special Projects TBRI Trauma-Informed Care Uncategorized

redpajama_set_name: RedPajamaCommonCrawl


How do we know if a population is evolving?
1. The traits within a population vary from individual to individual.
2. The variation must be heritable in some manner; not controlled completely by the environment.
4. Individuals with more favorable traits are better adapted to the environment, and therefore pass more genetic information to the next generation.
All four of Darwin's postulates can be confirmed within the firemouth cichlid population, which would confirm that evolution is occurring within the firemouth population. In fact, studies have shown that evolution is taking place at a very high rate in many cichlid populations, especially in the firemouth cichlids (7, 8, 9).
Darwin's second postulate, that variation is heritable, can be observed by the increase of various "dominant" traits over successive generations. In firemouth cichlids, most of this is due to competition between males and sexual selection by the females (2, 7, 8).
The third postulate that Darwin proposed was that there are differing survival and reproductive rates among the individuals within the population. This has been confirmed by various studies done on the long-term evolutionary change in coloration due to natural and sexual selection in firemouth cichlids (1, 4, 8, 9).
Darwin's fourth postulate is essentially a confirmation of the effects of the first three postulates. Based on the previous three postulates, scientists are able to document heritable variation within the population and differential mating success and survival. From these observations, the evolutionary change of the firemouth cichlid population can be determined.
The firemouth cichlid population is a good example of evolution in action. With a confirmation of all four of Darwin's postulates, the factual nature of firemouth evolutionary change is impossible to deny. These changes are primarily due to male-male competition (via fighting), sexual selection by the females, and various other behavioral, morphological and molecular changes.
(1) Baerends, G. P., and J. M. Baerends-Van Roon. 1950. An Introduction to the Study of the Ethology of the Cichlid Fishes. Behaviour. Supplement.
(2) Beeching, S. C., and Pike, R. E. 2010. Ontogenetic Color Change in the Firemouth Cichlid, Thorichthys Meeki. The American Society of Ichthyologists and Herpetologists.
(3) Chen, C., and Fernald, R. D. 2011. Visual Information Alone Changes Behavior and Physiology during Social Interactions in a Cichlid Fish (Astatotilapia burtoni). PLoS ONE.
(4) Dijkstra, P. D., and Groothuis, T. G. G. 2011. Male-Male Competition as a Force in Evolutionary Diversification: Evidence in Haplochromine Cichlid Fish. International Journal of Evolutionary Biology.
(5) Enquist, M. Leimar, O., Ljungberg, T., Mallner, Y., and Segerdhal, N. 1990. A test of the sequential assessment game:fighting in the cichlid fish Nannacara annomala. The Association for the Study of Animal Behavior.
(7) Kodric-Brown, A. 1998. Sexual Dichromatism and Temporary Color Changes in the Reproduction of Fishes. American Zoology.
(8) Maan, M. E., Hofker, K. D., van Alphen, J. J. M., and Seehausen, Ole. 2006. Sensory Drive in Cichlid Speciation. The American Naturalist.
(9) Nagl S., Tichy, H., Mayer, W. E.,Takezaki, N., Takahata, N. and Klein, J. 2000. The origin and age of haplochromine shes in Lake Victoria, East Africa. The Royal Society.
(10) Neil, S. J. 1984. Color Pattern Variability and Behavioral Correlates in the Firemouth Cichlid, Cichlasoma meeki. Copeia.
(11) Sugawara, T. Terai, Y., and Okada, N. 2002. Natural Selection of the Rhodopsin Gene During the Adaptive Radiation of East African Great Lakes Cichlid Fishes. Society for Molecular Biology and Evolution.


text:
News | Local
BOLD School District's division apparent as it starts new look at facilities needs
Roughly a third of those attending a public information meeting last week walked out when they learned they were to provide written comments on sticky notes instead of speaking directly to board members. Those who remained got an opportunity to speak, and they expressed concerns for the district's future.
Those who attended an informational meeting last week hosted by the BOLD School Board were invited to place comments on sticky notes on white sheets corresponding to six questions posed to the public on the district's facilities needs. Tom Cherveny / West Central Tribune
OLIVIA — Divisions in the BOLD School District were apparent when school board members hosted a public meeting to gather input on facilities needs on April 22.
Roughly a third of the estimated 60 or so participants walked out of the Olivia gymnasium together when they learned that it was not intended as an open forum for public comment.
School Board Chair Jill Hanson asked attendees to place their comments and questions on white paper sheets along the gym walls using sticky notes they had been given when they arrived. The comments and questions were to be placed on the sheets, each of which featured questions posed on the challenges facing the district, and why people opposed or supported the bond issue put before voters in the February referendum.
The board chair said the district would respond to the questions and answers on the school district's website .
After the formal meeting ended, many attendees lingered to discuss their thoughts on the BOLD School District's facilities needs. The school board hosted the meeting April 22 in the gymnasium in Olivia. Tom Cherveny / West Central Tribune
The district is starting a new effort to gather input on its facilities needs after voters in February rejected a $62.6 million bond seeking to build a new school to serve the communities of Bird Island , Lake Lillian and Olivia .
BOLD, Buffalo Lake-Hector-Stewart discuss academic collaboration, but not facilities School board members for the BOLD and Buffalo Lake-Hector-Stewart districts met to discuss ways they can work together. Both boards are interested in ways to expand opportunities for students, but there was no discussion on working together towards consolidation or a joint building program.
BOLD taking steps to address facilities needs, both immediate and long-term A contractor is set to provide input on immediate roofing needs while BOLD School Board members prepare for joint meeting with their Buffalo Lake-Hector-Stewart counterparts on possible cooperation.
BOLD School Board seeks path forward on massive facilities needs after $62.6M bond rejected BOLD School Board members are looking for a way forward to address the district's facilities needs after voters rejected a $62.6 million bond. Board members are open to discussions with neighboring districts and options such as remodeling, but face some urgency after hearing a report on deficiencies in current facilities.
Bird Island, Lake Lillian and Olivia voters in BOLD School District reject $62.6 million bond referendum Voters say no to bond referendum for new preK-12 facility, athletic and activities complex.
Terry Serbus was among those leading the charge out of the door. He expressed his frustration that comments and questions couldn't be raised directly at the meeting, and said that there was no transparency. "We told you what we wanted," said Serbus as he and others left.
The meeting format came as a surprise to some of the school board members as well.
Member Sandy Benson said she believed the meeting was to be a forum with opportunities for a back-and-forth dialogue.
BOLD School Board member Theresa Jacobs stands at the podium and invites those attending the meeting on the BOLD School District's facilities needs to come forward and have their say. Board chair Jill Hanson is at right. Tom Cherveny / West Central Tribune
Board member Theresa Jacobs approached the podium and invited participants who remained to take the opportunity to also come forward and express themselves.
A number of people did so.
Among the first was former school board member Jeff Benson. While he applauded the effort to gather public input on facilities needs, he too urged the board to hold an open conversation.
There's a need, he said, "for an actual, down-to-earth dialogue."
Participants also expressed concerns about the district's future due to the divisions and, especially, the need to address the facilities needs.
Jackie Edwards, speaking as a parent, said she was among those concerned for the district's future.
"We have to figure out how to do this and how to do it together," she said.
John O'Neill served on the district's steering committee prior to the referendum for a new school facility. He said he felt the process was "steered" and said the referendum showed the result.
"Eighty-one percent said no to a brand new school, and 19 percent could agree it was the best route to go. Someone failed," he said.
"It's time to start repairing things instead of putting a Band-Aid on," said O'Neill.
Participants expressed a wide range of views on sticky notes they posted at the BOLD School Board's meeting to gather information on the district's facilities needs on April 22 in Olivia. Tom Cherveny / West Central Tribune
Superintendent Dale Brandsoy said there were misperceptions about the format for the meeting, but emphasized that board members want public input and to provide answers to the questions out there. He urged participants to place their comments on the white sheets around the gymnasium, and they filled up with comments.
The comments ranged from concerns about the condition of the current facilities to the tax impact of building new facilities. "Taxes going tooooo high," stated one note. Concerns about public trust and the divisions in the district were apparent as well in the comments.
There was also an encouragement to board members to develop a plan to move forward: "Provide a new or remodeled building to give great education to students at an affordable price," said Susie Peterson, who signed her comment.
Related Topics: EDUCATIONOLIVIABIRD ISLANDLAKE LILLIANLAKE LILLIANBOLD PUBLIC SCHOOLS
Community task force to have a hand in budget-cutting process for Willmar Public Schools
Falling enrollment and the end of pandemic relief funds have resulted in a need for budget cuts at Willmar Public Schools. A community task force will have a hand in making the recommendations.
By Linda Vanderwerf
Donation to benefit Minnesota Veterans Homes, including in Montevideo
The Hutchinson Veterans of Foreign Wars Post 960 has donated $80,000 to benefit State Veterans Homes.
Six arrested, half pound of methamphetamine seized in narcotics investigation in Kandiyohi, Stearns counties
Sgt. Ross Ardoff, commander of the CEE-VI Drug and Gang Task Force, said six people were arrested in three cities after agents executed search warrants on Monday. The investigation remains active and more arrests are expected, according to a news release.
Schools & Students published Jan. 31, 2023
News about educational achievements among students from west central Minnesota.
By Donna Middleton
Tribune Notebook: Six Cards earn conference honors


A great post on cartoonist Mike Lynch's blog about Will Eisner's tenure on P*S Magazine for the U.S. Army. The post also features some great cover scans from Lynch's collection.
This page contains a single entry by GaryC published on May 4, 2007 3:19 PM.
IGN reviews 'Will Eisner: Portrait of a Sequential Artist' was the previous entry in this blog.
2007 Eisner Awards: Judges interview is the next entry in this blog.


text:
Reports in the local media Jazz to re-sign Exum
Thread starter Rubashov
KqWIN
FAILED STATE said:
I'll say it again. Just gimme more of Forrest. Forget Oni and Exum.
I like Forrest, but if he were to ever become a regular in a rotation teams might realize he's a 25% 3 point shooter and will surely punish us for that.
How about we play Butler instead of playing a broken and terrible example?
KqWIN said:
I mean...I never said they were comparable in performance. Danny Green is simply an example of how far you can go as long as you have the right skills and also a testament to how valuable the skillset you described is. Everybody is looking for a low maintenance, good defensive wing who can shoot well enough to not bomb your offense.
What you just described is not Danny Green though, who is an ELITE shooter, who had an established track record of winning basketball at the highest level of the NCAA, and who actually played near-elite defense. Oni's SOS in college was NEGATIVE, but more importantly, in the NBA he has been reeking dog ****. These are not comparable players.
We're talking about players that should only see the floor in blowouts so it's whatever. However, Exum can at least defend at an NBA level which is more than can be said of Oni. Or at least he could. He also demonstrated good lob chemistry with Rudy.
Do you understand how bad a basketball player has to be for me to make a comparison that is favorable to Dante Exum?
Reactions: homeytennis
Let them sag off of him, then. Dude is showing that he can punish a defense without bombing a 3. I have almost zero worries about him an effective rotation defense-first guy... even he's shooting in the low 30%s. And I think he'll get into the mid-30s.
But honestly, we're talking about players that should only see the floor in blowouts so it's whatever. But Exum can at least defend at an NBA level which is more than can be said of Oni. Or at least he could. He also demonstrated good lob chemistry with Rudy.
I am not saying Miye Oni is the same level. What I am saying is that they have similar roles as players and the role they play is highly valuable. They are there to to be lead wing defenders on defense and take catch and shoot 3's on offense. Anything beyond that is not really in their jurisdiction. Are you disagreeing their role on the court is different? There is no comparison in terms of caliber, performance, pedigree, or anything else besides their role on the court being made here. Miye Oni may not be good enough to be a starter on multiple championship level teams...but that's not the question here is it? The question is if he's good enough at his role to be on this roster. For me that's an solid yes.
Oni played about 350 real minutes last year, which is admittedly not a ton, but it was enough for me to feel confident that he won't mess things up. He blends well into a team that is stacked with perimeter players who don't defend and also want to shoot/handle the ball all the time. If this was a team that needs players to add playmaking I might feel different, but this is the exact situation that Oni can excel in because that is the last thing we need him to do well.
Quite frankly, that's all you're asking out of these out of rotation guys. When a rotation player is out you want someone to step in and keep things going smoothly. Oni did that last year which is why I believe he can do it again. Additionally, I don't think he's that far away from being solid everyday rotation level player. Like I said, if he was a little better on both ends that's a guy who plays for every team.
I don't think he really can...and if I'm an opposing team I am dying for the Jazz to try to beat me with Trent Forrest. Whether he's shooting wide open 3's or getting into the paint and trying to get his floater/lob game going that is a huge win for the opponent. To me, Forrest is in a tough situation because his offensive game is only passable when he has the ball, but he is also not good enough with the ball to warrant the ball on this team.
If he was shooting low 30's I could see it....but banking on him being a low 30's shooter is arguably a bigger leap than banking on Oni being a high 30's shooter. I just don't believe in his shot. Forrest was 25% in college and 26% as a pro (NBA, Summer League, Preseason).
Rubashov
Right now I'd have Forrest over Oni. Oni is done, next stop 2nd division in Spain or a post grad situation at some ivy league school.
Reactions: jom2003 and Douchebag K
I'm all for allowing the Forrest experiment, but the biggest problem (right now) is he's being thrown in for spot minutes and without a specific role (though I'll give Quin credit for throwing him out there with Mike and using him as a wing defender and not specifically as a PG). With Exum Quin would be fine throwing him out there on a high-profile guy or someone lighting us up. Quin hasn't gotten to that point with Forrest. I'd like to see how he holds up. I think if that's the route, we need to do this soon to answer the question and give experience. There's also the two-way issue and he wouldn't be available in the post-season. So if we could do that earlier (and if the cap issue of singing him to a regular deal is too costly) then if we could find out ASAP so we can waive Oni before the guarantee date (if financial constraints are an issue) and move Forrest to the regular roster.
Reactions: TheGoldStandard
TheGoldStandard
LogGrad98 said:
So we failed to use any of our assets to address our most glaring need during the off-season, so we'll instead bring back a player that has failed to produce anything of merit in his entire career, including being released by what may be the worst team in the league this year.
Sounds great! Sign him up!
I heard he's the only player in the league who can shut down Harden.
He played good defense that one time.
He shot 33% this year in summer league on roughly 4 attempts per, and his stroke looked much better than last year (still needs improvement, but you can tell he has worked a lot this offseason to improve).
If he is left open, I would not be surprised to see him make 3s at or around 33% based on what I saw this summer.
I don't think Oni belongs in the NBA.
TheGoldStandard said:
He shot 7/19 (37%) in 7 summer league games....but that's still only 19 attempts. When you're basically a 25% shooter your whole career it's going to take a lot more to convince me. Anything above 30% is very optimistic in my opinion because his total track record has him as a 25% shooter.
Oni belongs in the NBA and I think he did exactly what was expected of him last year. When players got injured he stepped in and we didn't miss a beat for the most part. Didn't have a great showing in the playoffs, but to me that showed me he wasn't good enough to make an impact in the playoffs, which is not the same thing as not being good enough for the roster.
Saint Cy of JFC
So far I've seen nothing from local (Jazz) media.
homeytennis
Saint Cy of JFC said:
Today is Sunday so I don't think the Jazz office is buzzing,


text:
Eureka Prizes announce four Sydney finalists
University of Sydney joins Sydney Science Festival
Search for courses, people, events and everything else ...
Home / News & opinion / News / July / University of Sydney joins Sydney Science Festival
2021: all news
STEM, health, medicine and music all feature
Our researchers are involved in a range of public events to celebrate National Science Week from 11 to 21 August.
We'll be highlighting our unique cross-disciplinary research in science, technology, innovation, health and medicine as part of the 10-day festival, with free public talks, panels and workshops – and everyone's welcome.
The University of Sydney's Mathematics and Science Ambassador Adam Spencer said "After a cracking debut last year, the Sydney Science Festival is poised to become one of Sydney's major cultural events."
"This year, the University is showcasing its unique approach to science, technology and health, with applications that go far beyond the lab," Spencer said.
"Our researchers will appear in a wide range of events, covering a wealth of topics – there's really something for everyone at this year's festival."
The inaugural Sydney Science Festival was held in 2015 as part of National Science Week – Australia's annual celebration of science and technology.
National Science Week is an initiative of the Inspiring Australia strategy, which was developed by the Australian Government to increase engagement and interest in the sciences.
Sydney Science Festival is poised to become one of Sydney's major cultural events. This year, the University is showcasing its unique approach to science, technology and health, with applications that go far beyond the lab
Adam Spencer
A few highlights showcasing our cross-disciplinary research
Nanotainment is the first chance the public have to see the research of the Australian Institute for Nanoscale Science and Technology presented.
Nanotainment
Tuesday 16 August
Associate Professor Mike Biercuk and Professors Zdenka Kuncic and David Reilly from our recently launched Australian Institute for Nanoscale Science and Technology will bring nanoscience to life in an evening of song, dance and performance in the Great Hall. This is the first chance the public have to see the research of this advanced facility presented.
Diabetes, Heart Disease, Obesity: a looming healthcare crisis?
In western Sydney, we'll be hosting a Sydney Ideas forum with the Westmead Institute for Medical Research discussing diabetes, heart disease and obesity. This special event will feature a panel of leading researchers discussing some of society's greatest health challenges.
2084: Future Medicine's Happier World
Wednesday 17 August
Discover a future where personalised medicine makes the world a healthier, happier place.
Hands-on activities and displays will follow this one-hour presentation from Professor David James from the Charles Perkins Centre.
Creating Art with Artificial Intelligence
Thursday 18 August
Fishburners in Ultimo
Learn how to create art with artificial intelligence with an evening of talks and discussion featuring our new Dean of The Conservatorium of Music, Anna Reid.
Hats on for the WiSA Hotseat
The Veterinary Science Conference Centre will host an evening workshop for young women interested in study and careers in STEM. The event will provide a chance to find out what motivates women who work in these industries, and will be followed by an informal networking session.
The Importance of Time Out
Hear Professor Mark Dadds present the latest research from the Brain and Mind Centre's Child Behaviour Unit Research Clinic. This Sydney Ideas event will take a look at the current scientific evidence behind strategies parents can use for children aged between two and 14. This is bound to be a popular event so make sure you book early so you don't miss out.
These events are only a small selection of the many we are involved in. Visit the Sydney Science Festival website to find out more.
Register for our Sydney Science Festival events
All across Sydney
Sydney Science Festival website
Resetting the table to halt expanding waistlines
Can farmers, producers and regulators work together at all points of the food supply chain to help curb Australia's growing obesity problem?
Eureka Prize for Associate Professor Michael J. Biercuk
Associate Professor Biercuk was recognised with the prestigious prize for contributions at the leading edge of quantum science research.
Scientists should take a leaf out of wellness bloggers' books
How can we distinguish credible wellness information from unfounded pseudoscience? And why is it that wellness gurus are often taken more seriously than scientists? Jackie Randles writes.


IHG® Rewards Club - eBooks - S.O.F.T.
When the storms come, what do you do? When the pain is unbearable, how do you survive? The answer is faithfaith that God loves you and cares for you, no matter what the outcome is. You must have faith that God will do what is best for you and the ones you are praying for. Faith even when you see the opposite of what you are praying for. Faith that God has a plan for you and the ones you love. If y… ou are deep down in a nasty pit and there seems to be no way out, it is time for you to take a stand and live the life God has designed specifically for you. The battle will be fierce, but you can do it! How do you get out of that pit? Faithunquestioning belief in God. Faith is the key that unlocks all the answers to your questions. God loves you like no other, and he wants you to understand what your faith means to him. This world and your heavenly Father need you and your faith. It is time for you to get up and fight. It is time for you to take a stand and defeat the enemy. We must unite and stand on faith together to experience victory after victory for his glory! If you are ready, I only have one question: Will you stand with me?


Please feel free to review some of our articles featuring Hallak Cleaners, fashion trends and clothing care tips. If you have further questions, please do not hesitate to contact us directly at info@hallak.com.
A wedding gown's journey down the aisle – and after its Big Day. Presented to you in a beautiful wedding blog by the owner / designer of Headpiece.com.
Recently, Hallak Cleaners won a very special first place award.
Joe Hallak was recently featured in an article about hard-to-clean garments. The key to safe cleaning is in the proper knowledge of the various processes and solvents.
Manhattan Bride article featuring Hallak Cleaners.
Cleaning up: Hallak Cleaners adjusting to the times, needs of the customers.
Before attempting to clean window treatments yourself, please review this helpful article on fighting drapery shrinkage. When in doubt, leave it to the professionals.
Fresh Start for Fall Donation Drive.
Hallak Cleaners requesting your help in a community clothing drive.
BergenCounty.com takes a look at our comprehensive list of services.
April 2013. John-Claude Hallak offers tip to the NY Times.
December 2012. Peachy Deegan trusts us to keep her sweaters looking their best.
December 2012, Peachy Deegan interview John-Claude on everything from family life to fabric care tips. Much like Whom You Know overall, there is a little bit of something for everyone. If you live in Manhattan, you should be visiting Peachy's page regularly. Thank you Peachy!
June 2012. On the first page of The Bergen Record's Better Living section, you can read about a special bride who walked into our store.
February 2012, Heather Zwain selected us as one of her Editor's Picks for (201) Magazine's Best of Bergen 2012!
December 2011, Our bridal consultant speaks with the WedAlert's Network Pretty Clever Bride regarding our pre and post wedding services.
Nov/Dec 2011, Joseph Hallak, Jr, offers his expert advice regarding this season's possible fashion dangers in regards to fabric care.
September 2011, Information blog regarding removing a stain from your wedding gown!
October 2011, Mr. John-Claude Hallak offers tips in this useful article!
August 2011, We offer some helpful information and tips for brides regarding what to do with the gown after the Big Day.
July 13, 2011, Ellen Wilkowe of The Bergen Record discusses fabric and leather care with the Hallaks.
May 2, 2011, Laura Martin (Asbury Press) reflects on the importance of proper bridal wear care.
April 25 2011, Whom You Know blogs her love for Hallak Cleaners again.
April 21, 2011, Three Manhattan Businesses Praised for being green, including Hallak Cleaners.
April 19, 2011, Ingrid M. Williams from Your Big Day (Event Planning) visited Hackensack location.
April 15, 2011, Whom You Know blog loves Hallak Cleaners for her cocktail dresses.
April 10, 2011, Recyclable hangers, reusable garment bags, biodegradable soaps bring in customers.
January 2011, Highlights Hallak Cleaners as a pioneer in the green cleaning effort.
October 27, 2010, John-Claude Hallak combined his father's attention to detail and his own business ideas to keep the family dry cleaning business healthy.
October 30, 2009, the the American Drycleaner Magazine, ran part 3 of their article, Fall Fashion Extra: When Garments Sparkle, Drycleaners Cringe, mentioning Hallak's name.
October 29, 2009, the American Drycleaner Magazine, ran part 2 of their article, Styles of the Season, mentioning Hallak's name.
October 28, 2009, the American Drycleaner Magazine, ran part 1 of their article, Styles of the Season, mentioning Hallak's name.
August 31, 2009, the blog Business PR, posts the press release about Hallak's new technology upgrade with the help of Miles Technologies.
August 31, 2009, the blog Textile Rumors, posts the press release about Hallak's new technology upgrade with the help of Miles Technologies.
August 31, 2009, a press release described Hallak and our new improvements to our plant with IT support from Miles Technologies.
August 24, 2009, Bethenny Frankel from the Real Housewives of NY just Tweeted about Hallak on Twitter. She said that she "is so thrilled with James at Hallak Cleaners on 2nd ave/64th. They work so hard and can get almost any stain out!!!" Follow Hallak on Twitter @hallakcleaners!
July 12, 2009, the Texarkana Gazette in Texas ran an Associated Press story about Hallak's wedding gown care.
June 30, 2009, Weddingbee Blog mentions Hallak's Bridal Emergency Kit in her blog.
April 29, 2009, The Bridal Wishlist Blog talks about Hallak's participation in the B-List.
March 8, 2009, PR Web releases news about Hallak's new Couture Cleaning for Charity Program. Read the press release here.
February 13, 2009, Joe Hallak talks about how business is doing in current state of the economy in The New York Times.
February 4, 2009, Joe Hallak offered sweater care tips to the Style Mama blog.
January 11, 2009, Joe Hallak flew down to a fellow Leading Cleaners International member in Metairie, LA to help them recover after Hurricane Katrina. Read about the adventures of the LCI during the recovery here.
November 30, 2008, Hallak is mentioned in an article in the St. Petersburg Times in St. Petersburg, FL.
November 20, 2008 John-Claude Hallak is quoted in the article "Tales From the Couture Dry Cleaners" in the Wall Street Journal. Click here to read the article.
August 11, 2008, the blog From "I Will" To "I Do" recommends Hallak's Gown Preservation Services. Click here to read the entry.
August 21, 2008, Joseph Hallak Jr. is quoted on drapery cleaning in The New York Sun. Click here to read the article.
Hallak's Bridal Emergency Kit Gets Blogged – AGAIN!
July 21, 2008 Lela New York, a couture invitation design house, bloggs about our Bridal Emergency Kit. Click here to read the post.
July 1, 2008 BBC News North America business correspondent talks about dry cleaning business facing the most severe test in their history, spotlighting Joseph Hallak, Jr. Click here to read the story.
July 1, 2008 iVillage posted about Hallak Cleaner's wedding gown donation to The Bridal Garden. Read it here.
June 10, 2008 (201) Bride includes and article on gown preservation on their website. Click here to read it.
June 10, 2008 Newsday features a blurb and color photo on Hallak's Bridal Emergency Kit. Click here to see the Hallak Newsday article.
June 3, 2008, the Daily Sentinel in Texas ran a story on Hallak's Gown Preservation Service written by The Associated Press. Click here to read the story. And The Canadian Pres ran the same story on June 5, 2008. Click here to see it.
May 25, 2008, Joseph Hallak Jr. appeared on ABC to demonstrate more on emergency spotting on your wedding dress on your wedding day. Click here and scroll down to read all about the segment.
May 22, 2008, The Associated Press wrote a release about quick stain removal in which Joesph Hallak, Jr. was mentioned. Read the story here.
Hallak was mentioned in Rachel's Handbags Blog on About.com. Click here to read the post from May 12, 2008.
April 13, 2008 The Bergen Record ran a story about green cleaning in which Hallak was mentioned. Click here to read it.
April 13, 2008 The Bergen Record ran an article on hangers in which Hallak was mentioned for how we recycle ours. Read the story by clicking here.
April 9, 2008, Hallak is mentioned in an article on iVillage for Gown Cleaning. Click here to read Sample Sales: Cleaning Your Gownon iVillage.
March 30, 2008, Hallak's Bridal Emergency Kit was talked about in the Sunday News Journal, DE. Click here to read the Sunday News Journal article.
Read about how we clean handbags in the March 20, 2008 edition of the New York Post here.
Hallak Cleaners is recognized by The Bergen Record as a distinguished couture dry cleaner. Read the full article by clicking here.
September 2001, Hallak was visited by an International Dry Cleaners Fellow, Kelly Smith. Click here to read the story.
Hallak Cleaners is recognized by The Knot as a premier cleaner of Wedding Gowns, and has placed us on its recommended list.
Spruce Magazine, a publication standard in the industry, named Hallak Cleaners among the nations ten best. Their profile recounted an incident which could also qualify Hallak as the safest. Some years ago, a client brought in an outrageously expensive Chanel bag to be cleaned. Without a moment's hesitation, President John-Claude Hallak placed it in the store vault for safety until it was serviced. At Hallak, this kind of customer attention is par for the course, and has been since we began operations as a family-run business in 1963. What makes Hallak so special is the care and the people they employ. Unlike most cleaners with only one or two cleaning methods available, Hallak has four to satisfy the varying cleaning requirements of a cotton sweater, a beaded silk gown, an Armani suit and a leather jacket. Whereas most cleaners distill their cleaning solutions only after 4-5 uses, we distill ours after every use. And, because poor pressing is so critical to a perfectly cleaned and finished garment, we hire only the best, most experienced professionals and then refine their techniques to meet our exacting standards. We give our customers more – more advanced technologies and more qualified, caring employees.
Hallak is the recipient of the 2002 Robert Santo Environmental Awareness Award given by the New Jersey Small Business Compliance Advisory Panel, in cooperation with the New Jersey Department of Environmental Protection. Hallak is one of 2 businesses in the state to receive this prestigious award based on demonstrating exemplary environmental responsibility. We are proud to be recognized by the State of New Jersey for our commitment to the protection on our natural resources.