Merge pull request #911 from annando/master

target="_blank" and api improvements
This commit is contained in:
Tobias Diekershoff 2014-02-16 14:15:44 +01:00
commit 3bbe7a75ec
10 changed files with 100 additions and 63 deletions

View file

@ -952,8 +952,6 @@
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$sql_extra = '';
if ($max_id > 0)
$sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
@ -1031,8 +1029,6 @@
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
if ($max_id > 0)
$sql_extra = 'AND `item`.`id` <= '.intval($max_id);
if ($exclude_replies > 0)
@ -1100,7 +1096,6 @@
logger('API: api_statuses_show: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$conversation = (x($_REQUEST,'conversation')?1:0);
$sql_extra = '';
@ -1169,8 +1164,6 @@
logger('API: api_conversation_show: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$sql_extra = '';
if ($max_id > 0)
@ -1225,8 +1218,6 @@
logger('API: api_statuses_repeat: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`nick` as `reply_author`,
`contact`.`name`, `contact`.`photo` as `reply_photo`, `contact`.`url` as `reply_url`, `contact`.`rel`,
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
@ -1328,8 +1319,6 @@
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
// Ugly code - should be changed
$myurl = $a->get_baseurl() . '/profile/'. $a->user['nickname'];
$myurl = substr($myurl,strpos($myurl,'://')+3);
@ -1626,18 +1615,18 @@
function api_get_entitities($text, $bbcode) {
/*
To-Do:
* remove links to pictures if they are links of a picture
* Some video stuff isn't recognized
* Links at the first character of the post
* different sizes of pictures
* caching picture data (using the id for that?) (See privacy_image_cache)
*/
$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:true);
$include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
// To-Do
// if (!$include_entities OR ($include_entities == "false"))
// return false;
if ($include_entities != "true")
return array();
// Change pure links in text to bbcode uris
$bbcode = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2]$2[/url]', $bbcode);
$entities = array();
$entities["hashtags"] = array();
@ -1645,14 +1634,24 @@
$entities["urls"] = array();
$entities["user_mentions"] = array();
$bbcode = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$bbcode);
$URLSearchString = "^\[\]";
$bbcode = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'#$2',$bbcode);
$bbcode = preg_replace("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$bbcode);
//$bbcode = preg_replace("/\[url\](.*?)\[\/url\]/ism",'[url=$1]$1[/url]',$bbcode);
$bbcode = preg_replace("/\[video\](.*?)\[\/video\]/ism",'[url=$1]$1[/url]',$bbcode);
$bbcode = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
'[url=https://www.youtube.com/watch?v=$1]https://www.youtube.com/watch?v=$1[/url]', $bbcode);
$bbcode = preg_replace("/\[youtube\](.*?)\[\/youtube\]/ism",'[url=$1]$1[/url]',$bbcode);
$Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
'[url=https://vimeo.com/$1]https://vimeo.com/$1[/url]', $bbcode);
$bbcode = preg_replace("/\[vimeo\](.*?)\[\/vimeo\]/ism",'[url=$1]$1[/url]',$bbcode);
$bbcode = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $bbcode);
$URLSearchString = "^\[\]";
//preg_match_all("/\[url\]([$URLSearchString]*)\[\/url\]/ism", $bbcode, $urls1);
preg_match_all("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $bbcode, $urls);
@ -1716,8 +1715,8 @@
$image = @imagecreatefromstring($img_str);
if ($image) {
$entities["media"][] = array(
"id" => $start,
"id_str" => (string)$start,
"id" => $start+1,
"id_str" => (string)$start+1,
"indices" => array($start, $start+strlen($url)),
"media_url" => $url,
"media_url_https" => $url,
@ -1792,7 +1791,8 @@
// Workaround for ostatus messages where the title is identically to the body
//$statusbody = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 5, true), 0));
$statusbody = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 2, true), 0));
$html = bbcode(api_clean_plain_items($item['body']), false, false, 2, true);
$statusbody = trim(html2plain($html, 0));
$statustitle = trim($item['title']);
@ -1836,7 +1836,12 @@
// Retweets are only valid for top postings
if (($item['owner-link'] != $item['author-link']) AND ($item["id"] == $item["parent"])) {
// It doesn't work reliable with the link if its a feed
$IsRetweet = ($item['owner-link'] != $item['author-link']);
if ($IsRetweet)
$IsRetweet = (($item['owner-name'] != $item['author-name']) OR ($item['owner-avatar'] != $item['author-avatar']));
if ($IsRetweet AND ($item["id"] == $item["parent"])) {
$retweeted_status = $status;
$retweeted_status["user"] = api_get_user($a,$item["author-link"]);
@ -2385,25 +2390,34 @@ function api_get_nick($profile) {
}
function api_clean_plain_items($Text) {
$include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
if ($include_entities == "true") {
$URLSearchString = "^\[\]";
$Text = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'#$2',$Text);
$Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'[url=$1]$1[/url]',$Text);
}
$Text = preg_replace_callback("((.*?)\[class=(.*?)\](.*?)\[\/class\])ism","api_cleanup_share",$Text);
return($Text);
}
function api_cleanup_share($shared) {
if ($shared[2] != "type-link")
return($shared[3]);
if ($shared[2] != "type-link")
return($shared[0]);
if (!preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$shared[3], $bookmark))
return($shared[3]);
if (!preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$shared[3], $bookmark))
return($shared[0]);
$title = "";
$link = "";
$title = "";
$link = "";
if (isset($bookmark[2][0]))
$title = $bookmark[2][0];
if (isset($bookmark[2][0]))
$title = $bookmark[2][0];
if (isset($bookmark[1][0]))
$link = $bookmark[1][0];
if (isset($bookmark[1][0]))
$link = $bookmark[1][0];
if (strpos($shared[1],$title) !== false)
$title = "";
@ -2411,16 +2425,16 @@ function api_cleanup_share($shared) {
if (strpos($shared[1],$link) !== false)
$link = "";
$text = trim($shared[1]);
$text = trim($shared[1]);
//if (strlen($text) < strlen($title))
if (($text == "") AND ($title != ""))
$text .= "\n\n".trim($title);
if ($link != "")
$text .= "\n".trim($link);
if ($link != "")
$text .= "\n".trim($link);
return(trim($text));
return(trim($text));
}
function api_best_nickname(&$contacts) {

View file

@ -322,7 +322,7 @@ function bb_ShareAttributes($match) {
if ($avatar != "")
$headline .= '<img src="'.$avatar.'" height="32" width="32" >';
$headline .= sprintf(t('<span><a href="%s" target="external-link">%s</a> wrote the following <a href="%s" target="external-link">post</a>'.$reldate.':</span>'), $profile, $author, $link);
$headline .= sprintf(t('<span><a href="%s" target="_blank">%s</a> wrote the following <a href="%s" target="_blank">post</a>'.$reldate.':</span>'), $profile, $author, $link);
$headline .= "</div>";
@ -369,7 +369,7 @@ function bb_ShareAttributesDiaspora($match) {
$headline .= '<span><b>'.html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').$userid.':</b></span>';
//$headline .= sprintf(t('<span><b>'.
// html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').
// '<a href="%s" target="external-link">%s</a>%s:</b></span>'), $profile, $userid, $posted);
// '<a href="%s" target="_blank">%s</a>%s:</b></span>'), $profile, $userid, $posted);
$headline .= "</div>";
$text = trim($match[1]);
@ -423,7 +423,7 @@ function bb_ShareAttributesForExport($match) {
$headline = '<div class="shared_header">';
$headline .= sprintf(t('<span><b>'.
html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').
'<a href="%s" target="external-link">%s</a>%s:</b></span>'), $link, $userid, $posted);
'<a href="%s" target="_blank">%s</a>%s:</b></span>'), $link, $userid, $posted);
$headline .= "</div>";
$text = trim($match[1]);
@ -533,6 +533,23 @@ function GetProfileUsername($profile, $username) {
return($username);
}
function RemovePictureLinks($match) {
$ch = @curl_init($match[2]);
@curl_setopt($ch, CURLOPT_NOBODY, true);
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; Friendica)");
@curl_exec($ch);
$curl_info = @curl_getinfo($ch);
if (substr($curl_info["content_type"], 0, 6) == "image/")
$text = "[url=".$match[2]."]".$match[2]."[/url]";
else
$text = "[url=".$match[1]."]".$match[1]."[/url]";
return($text);
}
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendica - Mike Macgirvin
@ -632,19 +649,21 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$forplaintext)
$Text = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1<a href="$2" target="external-link">$2</a>', $Text);
else
$Text = preg_replace("(\[url\](.*?)\[\/url\])ism"," $1 ",$Text);
$Text = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1<a href="$2" target="_blank">$2</a>', $Text);
else {
$Text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism"," $1 ",$Text);
$Text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'RemovePictureLinks', $Text);
}
if ($tryoembed)
$Text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism",'tryoembed',$Text);
$Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="external-link">$1</a>', $Text);
$Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="external-link">$2</a>', $Text);
$Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank">$1</a>', $Text);
$Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="_blank">$2</a>', $Text);
//$Text = preg_replace("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank">$2</a>', $Text);
// Red compatibility, though the link can't be authenticated on Friendica
$Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a href="$1" target="external-link">$2</a>', $Text);
$Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a href="$1" target="_blank">$2</a>', $Text);
// we may need to restrict this further if it picks up too many strays
@ -812,9 +831,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryoembed', $Text);
} else {
$Text = preg_replace("/\[video\](.*?)\[\/video\]/",
'<a href="$1" target="external-link">$1</a>', $Text);
'<a href="$1" target="_blank">$1</a>', $Text);
$Text = preg_replace("/\[audio\](.*?)\[\/audio\]/",
'<a href="$1" target="external-link">$1</a>', $Text);
'<a href="$1" target="_blank">$1</a>', $Text);
}
// html5 video and audio
@ -840,7 +859,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="https://www.youtube.com/embed/$1" frameborder="0" ></iframe>', $Text);
else
$Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
'<a href="https://www.youtube.com/watch?v=$1" target="external-link">https://www.youtube.com/watch?v=$1</a>', $Text);
'<a href="https://www.youtube.com/watch?v=$1" target="_blank">https://www.youtube.com/watch?v=$1</a>', $Text);
if ($tryoembed) {
$Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text);
@ -854,7 +873,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="https://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text);
else
$Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
'<a href="https://vimeo.com/$1" target="external-link">https://vimeo.com/$1</a>', $Text);
'<a href="https://vimeo.com/$1" target="_blank">https://vimeo.com/$1</a>', $Text);
// $Text = preg_replace("/\[youtube\](.*?)\[\/youtube\]/", '<object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/$1" ><param name="movie" value="http://www.youtube.com/v/$1"></param><!--[if IE]><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" width="425" height="350" /><![endif]--></object>', $Text);

View file

@ -558,13 +558,13 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
$tag["url"] = $searchpath.strtolower($tag["term"]);
if ($tag["type"] == TERM_HASHTAG) {
$hashtags[] = "#<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$hashtags[] = "#<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$prefix = "#";
} elseif ($tag["type"] == TERM_MENTION) {
$mentions[] = "@<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$mentions[] = "@<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$prefix = "@";
}
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
}
/*foreach(explode(',',$item['tag']) as $tag){

View file

@ -826,6 +826,10 @@ function add_fcontact($arr,$update = false) {
function scale_external_images($srctext, $include_link = true, $scale_replace = false) {
// Suppress "view full size"
if (intval(get_config('system','no_view_full_size')))
$include_link = false;
$a = get_app();
// Picture addresses can contain special characters

View file

@ -968,7 +968,7 @@ if(! function_exists('linkify')) {
* @param string $s
*/
function linkify($s) {
$s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' <a href="$1" target="external-link">$1</a>', $s);
$s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' <a href="$1" target="_blank">$1</a>', $s);
$s = preg_replace("/\<(.*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism",'<$1$2=$3&$4>',$s);
return($s);
}}
@ -1301,13 +1301,13 @@ function prepare_body(&$item,$attach = false) {
$tag["url"] = $searchpath.strtolower($tag["term"]);
if ($tag["type"] == TERM_HASHTAG) {
$hashtags[] = "#<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$hashtags[] = "#<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$prefix = "#";
} elseif ($tag["type"] == TERM_MENTION) {
$mentions[] = "@<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$mentions[] = "@<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$prefix = "@";
}
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"external-link\">".$tag["term"]."</a>";
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
}
}
@ -1418,7 +1418,7 @@ function prepare_body(&$item,$attach = false) {
$title = ((strlen(trim($mtch[4]))) ? escape_tags(trim($mtch[4])) : escape_tags($mtch[1]));
$title .= ' ' . $mtch[2] . ' ' . t('bytes');
$as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="external-link" >' . $icon . '</a>';
$as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="_blank" >' . $icon . '</a>';
}
}
}

View file

@ -8,7 +8,7 @@
{{if $event.item.author_name}}<a href="{{$event.item.author_link}}" ><img src="{{$event.item.author_avatar}}" height="32" width="32" />{{$event.item.author_name}}</a>{{/if}}
{{$event.html}}
{{if $event.item.plink}}<a href="{{$event.plink.0}}" title="{{$event.plink.1}}" target="external-link" class="plink-event-link icon s22 remote-link"></a>{{/if}}
{{if $event.item.plink}}<a href="{{$event.plink.0}}" title="{{$event.plink.1}}" target="_blank" class="plink-event-link icon s22 remote-link"></a>{{/if}}
{{if $event.edit}}<a href="{{$event.edit.0}}" title="{{$event.edit.1}}" class="edit-event-link icon s22 pencil"></a>{{/if}}
</div>
<div class="clear"></div>

View file

@ -21,7 +21,7 @@
{{if $event.is_first}}<hr /><a name="link-{{$event.j}}" ><div class="event-list-date">{{$event.d}}</div></a>{{/if}}
{{if $event.item.author_name}}<a href="{{$event.item.author_link}}" ><img src="{{$event.item.author_avatar}}" height="32" width="32" />{{$event.item.author_name}}</a>{{/if}}
{{$event.html}}
{{if $event.item.plink}}<a href="{{$event.plink.0}}" title="{{$event.plink.1}}" target="external-link" class="plink-event-link icon s22 remote-link"></a>{{/if}}
{{if $event.item.plink}}<a href="{{$event.plink.0}}" title="{{$event.plink.1}}" target="_blank" class="plink-event-link icon s22 remote-link"></a>{{/if}}
{{if $event.edit}}<a href="{{$event.edit.0}}" title="{{$event.edit.1}}" class="edit-event-link icon s22 pencil"></a>{{/if}}
</div>
<div class="clear"></div>

View file

@ -34,7 +34,7 @@
{{if $marital}}<dl class="marital"><dt class="marital-label"><span class="heart">&hearts;</span>{{$marital}}</dt><dd class="marital-text">{{$profile.marital}}</dd></dl>{{/if}}
{{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url"><a href="{{$profile.homepage}}" target="external-link">{{$profile.homepage}}</a></dd></dl>{{/if}}
{{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url"><a href="{{$profile.homepage}}" target="_blank">{{$profile.homepage}}</a></dd></dl>{{/if}}
{{include file="diaspora_vcard.tpl"}}

View file

@ -75,7 +75,7 @@
</div>
{{/if}}
{{if $item.plink}}
<div class="wall-item-links-wrapper"><a href="{{$item.plink.href}}" title="{{$item.plink.title}}" target="external-link" class="icon remote-link{{$item.sparkle}}"></a></div>
<div class="wall-item-links-wrapper"><a href="{{$item.plink.href}}" title="{{$item.plink.title}}" target="_blank" class="icon remote-link{{$item.sparkle}}"></a></div>
{{/if}}
{{if $item.edpost}}
<a class="editpost icon pencil" href="{{$item.edpost.0}}" title="{{$item.edpost.1}}"></a>

View file

@ -52,7 +52,7 @@
{{if $marital}}<dl class="marital"><dt class="marital-label"><span class="heart">&hearts;</span>{{$marital}}</dt><dd class="marital-text">{{$profile.marital}}</dd></dl>{{/if}}
{{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url"><a href="{{$profile.homepage}}" target="external-link">{{$profile.homepage}}</a></dd></dl>{{/if}}
{{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url"><a href="{{$profile.homepage}}" target="_blank">{{$profile.homepage}}</a></dd></dl>{{/if}}
{{include file="diaspora_vcard.tpl"}}