public static function ConnectUrl($Provider, $Secure = FALSE, $Callback = TRUE)
 {
     if (!is_array($Provider)) {
         $Provider = self::GetProvider($Provider);
     }
     if (!is_array($Provider)) {
         return FALSE;
     }
     $Url = $Provider['AuthenticateUrl'];
     $Query = array('client_id' => $Provider['AuthenticationKey']);
     if ($Secure) {
         include_once dirname(__FILE__) . '/functions.jsconnect.php';
         $Query['timestamp'] = JsTimestamp();
         $Query['signature'] = JsHash($Query['timestamp'] . $Provider['AssociationSecret'], GetValue('HashType', $Provider));
     }
     if ($Target = Gdn::Request()->Get('Target')) {
         $Query['Target'] = $Target;
     } else {
         $Query['Target'] = '/' . ltrim(Gdn::Request()->Path(), '/');
     }
     if (StringBeginsWith($Query['Target'], '/entry/signin')) {
         $Query['Target'] = '/';
     }
     $Result = $Url . (strpos($Url, '?') === FALSE ? '?' : '&') . http_build_query($Query);
     if ($Callback) {
         $Result .= '&callback=?';
     }
     return $Result;
 }
function WriteJsConnect($User, $Request, $ClientID, $Secret, $Secure = TRUE)
{
    $User = array_change_key_case($User);
    // Error checking.
    if ($Secure) {
        // Check the client.
        if (!isset($Request['client_id'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'The client_id parameter is missing.');
        } elseif ($Request['client_id'] != $ClientID) {
            $Error = array('error' => 'invalid_client', 'message' => "Unknown client {$Request['client_id']}.");
        } elseif (!isset($Request['timestamp']) && !isset($Request['signature'])) {
            if (is_array($User) && count($User) > 0) {
                // This isn't really an error, but we are just going to return public information when no signature is sent.
                $Error = array('name' => $User['name'], 'photourl' => @$User['photourl']);
            } else {
                $Error = array('name' => '', 'photourl' => '');
            }
        } elseif (!isset($Request['timestamp']) || !is_numeric($Request['timestamp'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'The timestamp parameter is missing or invalid.');
        } elseif (!isset($Request['signature'])) {
            $Error = array('error' => 'invalid_request', 'message' => 'Missing  signature parameter.');
        } elseif (($Diff = abs($Request['timestamp'] - JsTimestamp())) > JS_TIMEOUT) {
            $Error = array('error' => 'invalid_request', 'message' => 'The timestamp is invalid.');
        } else {
            // Make sure the timestamp hasn't timed out.
            $Signature = md5($Request['timestamp'] . $Secret);
            if ($Signature != $Request['signature']) {
                $Error = array('error' => 'access_denied', 'message' => 'Signature invalid.');
            }
        }
    }
    if (isset($Error)) {
        $Result = $Error;
    } elseif (is_array($User) && count($User) > 0) {
        if ($Secure === NULL) {
            $Result = $User;
        } else {
            $Result = SignJsConnect($User, $ClientID, $Secret, TRUE);
        }
    } else {
        $Result = array('name' => '', 'photourl' => '');
    }
    $Json = json_encode($Result);
    if (isset($Request['callback'])) {
        header("Content-Type: application/javascript");
        echo "{$Request['callback']}({$Json});";
    } else {
        header("Content-Type: application/json");
        echo $Json;
    }
}