= 3) ? '' : '/') . (($achar === '?') ? '?f=&' : '&') . 'zid=' . urlencode($myaddr);
	else
		$zurl = $s;
	// put fragment at the end
	if($fragment)
		$zurl .= '#' . $fragment;
	$arr = [
			'url' => $s,
			'zid' => urlencode($myaddr),
			'result' => $zurl
	];
	/**
	 * @hooks zid
	 *   Called when adding the observer's zid to a URL.
	 *   * \e string \b url - url to accept zid
	 *   * \e string \b zid - urlencoded zid
	 *   * \e string \b result - the return string we calculated, change it if you want to return something else
	 */
	call_hooks('zid', $arr);
	return $arr['result'];
}
function strip_query_param($s,$param) {
	return preg_replace('/[\?&]' . $param . '=(.*?)(&|$)/ism','$2',$s);
}
function strip_zids($s) {
	return preg_replace('/[\?&]zid=(.*?)(&|$)/ism','$2',$s);
}
function strip_owt($s) {
	return preg_replace('/[\?&]owt=(.*?)(&|$)/ism','$2',$s);
}
function strip_zats($s) {
	return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
}
function strip_escaped_zids($s) {
	$x = preg_replace('/&\;zid=(.*?)(&|$)/ism','$2',$s);
	return strip_query_param($x,'f');
}
function clean_query_string($s = '') {
	$x = strip_zids(($s) ? $s : \App::$query_string);
	$x = strip_owt($x);
	$x = strip_zats($x);
	$x = strip_query_param($x,'sort');
	return strip_query_param($x,'f');
}
/**
 * zidify_callback() and zidify_links() work together to turn any HTML a tags with class="zrl" into zid links
 * These will typically be generated by a bbcode '[zrl]' tag. This is done inside prepare_text() rather than bbcode()
 * because the latter is used for general purpose conversions and the former is used only when preparing text for
 * immediate display.
 *
 * @TODO Issues: Currently the order of HTML parameters in the text is somewhat rigid and inflexible.
 *    We assume it looks like \ and will not work if zrl and href appear in a different order.
 *
 * @param array $match
 * @return string
 */
function zidify_callback($match) {
	$arr = [ 'zid' => ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ];
	call_hooks('zidify', $arr);
	$replace = ' ((strpos($match[1],'zrl')) ? true : false), 'url' => $match[2] ];
	call_hooks('zidify', $arr);
	$replace = ' ? zid($arr['url']) : $arr['url']) . ') $hubloc,
			'url' => \App::$query_string,
			'session' => $_SESSION
	];
	/**
	 * @hooks magic_auth_success
	 *   Called when a magic-auth was successful.
	 *   * \e array \b xchan
	 *   * \e string \b url
	 *   * \e array \b session
	 */
	call_hooks('magic_auth_success', $arr);
	\App::set_observer($hubloc);
	require_once('include/security.php');
	\App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
	if(! get_config('system', 'hide_owa_greeting'))
		info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name']));
	logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
}
 $hubloc,
			'url' => \App::$query_string,
			'session' => $_SESSION
	];
	/**
	 * @hooks magic_auth_success
	 *   Called when a magic-auth was successful.
	 *   * \e array \b xchan
	 *   * \e string \b url
	 *   * \e array \b session
	 */
	call_hooks('magic_auth_success', $arr);
	\App::set_observer($hubloc);
	require_once('include/security.php');
	\App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
	if(! get_config('system', 'hide_owa_greeting'))
		info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),\App::get_hostname(), $hubloc['xchan_name']));
	logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
}