<?php
/**
* @file include/widgets.php
*
* @brief This file contains the widgets.
*/
require_once('include/dir_fns.php');
require_once('include/contact_widgets.php');
function widget_profile($args) {
$a = get_app();
$block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
return profile_sidebar($a->profile, $block, true);
}
// FIXME The problem with the next widget is that we don't have a search function for webpages that we can send the links to.
// Then we should also provide an option to search webpages and conversations.
function widget_tagcloud($args) {
$o = '';
//$tab = 0;
$a = get_app();
$uid = $a->profile_uid;
$count = ((x($args,'count')) ? intval($args['count']) : 24);
$flags = 0;
$type = TERM_CATEGORY;
// FIXME there exists no $authors variable
$r = tagadelic($uid, $count, $authors, $flags, ITEM_WEBPAGE, $type);
if($r) {
$o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">';
foreach($r as $rr) {
$o .= '<span class="tag'.$rr[2].'">'.$rr[0].'</span> ' . "\r\n";
}
$o .= '</div></div>';
}
return $o;
}
function widget_collections($args) {
require_once('include/group.php');
$mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation');
switch($mode) {
case 'conversation':
$every = argv(0);
$each = argv(0);
$edit = true;
$current = $_REQUEST['gid'];
$abook_id = 0;
$wmode = 0;
break;
case 'connections':
$every = 'connections';
$each = 'group';
$edit = true;
$current = $_REQUEST['gid'];
$abook_id = 0;
$wmode = 0;
case 'groups':
$every = 'connections';
$each = argv(0);
$edit = false;
$current = intval(argv(1));
$abook_id = 0;
$wmode = 1;
break;
case 'abook':
$every = 'connections';
$each = 'group';
$edit = false;
$current = 0;
$abook_id = get_app()->poi['abook_xchan'];
$wmode = 1;
break;
default:
return '';
break;
}
return group_side($every, $each, $edit, $current, $abook_id, $wmode);
}
function widget_appselect($arr) {
return replace_macros(get_markup_template('app_select.tpl'),array(
'$title' => t('Apps'),
'$system' => t('System'),
'$authed' => ((local_channel()) ? true : false),
'$personal' => t('Personal'),
'$new' => t('Create Personal App'),
'$edit' => t('Edit Personal App')
));
}
function widget_suggestions($arr) {
if((! local_channel()) || (! feature_enabled(local_channel(),'suggest')))
return '';
require_once('include/socgraph.php');
$r = suggestion_query(local_channel(),get_observer_hash(),0,20);
if(! $r) {
return;
}
$arr = array();
// Get two random entries from the top 20 returned.
// We'll grab the first one and the one immediately following.
// This will throw some entropy intot he situation so you won't
// be looking at the same two mug shots every time the widget runs
$index = ((count($r) > 2) ? mt_rand(0,count($r) - 2) : 0);
for($x = $index; $x <= ($index+1); $x ++) {
$rr = $r[$x];
if(! $rr['xchan_url'])
break;
$connlnk = z_root() . '/follow/?url=' . $rr['xchan_addr'];
$arr[] = array(
'url' => chanlink_url($rr['xchan_url']),
'profile' => $rr['xchan_url'],
'name' => $rr['xchan_name'],
'photo' => $rr['xchan_photo_m'],
'ignlnk' => z_root() . '/suggest?ignore=' . $rr['xchan_hash'],
'conntxt' => t('Connect'),
'connlnk' => $connlnk,
'ignore' => t('Ignore/Hide')
);
}
$o = replace_macros(get_markup_template('suggest_widget.tpl'),array(
'$title' => t('Suggestions'),
'$more' => t('See more...'),
'$entries' => $arr
));
return $o;
}
function widget_follow($args) {
if(! local_channel())
return '';
$a = get_app();
$uid =$a->channel['channel_id'];
$r = q("select count(*) as total from abook where abook_channel = %d and not (abook_flags & %d)>0 ",
intval($uid),
intval(ABOOK_FLAG_SELF)
);
if($r)
$total_channels = $r[0]['total'];
$limit = service_class_fetch($uid,'total_channels');
if($limit !== false) {
$abook_usage_message = sprintf( t("You have %1$.0f of %2$.0f allowed connections."), $total_channels, $limit);
}
else {
$abook_usage_message = '';
}
return replace_macros(get_markup_template('follow.tpl'),array(
'$connect' => t('Add New Connection'),
'$desc' => t('Enter the channel address'),
'$hint' => t('Example: bob@example.com, http://example.com/barbara'),
'$follow' => t('Connect'),
'$abook_usage_message' => $abook_usage_message
));
}
function widget_notes($arr) {
if(! local_channel())
return '';
if(! feature_enabled(local_channel(),'private_notes'))
return '';
$text = get_pconfig(local_channel(),'notes','text');
$o = replace_macros(get_markup_template('notes.tpl'), array(
'$banner' => t('Notes'),
'$text' => $text,
'$save' => t('Save'),
));
return $o;
}
function widget_savedsearch($arr) {
if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch')))
return '';
$a = get_app();
$search = ((x($_GET,'search')) ? $_GET['search'] : '');
if(x($_GET,'searchsave') && $search) {
$r = q("select * from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
);
if(! $r) {
q("insert into `term` ( `uid`,`type`,`term` ) values ( %d, %d, '%s') ",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
);
}
}
if(x($_GET,'searchremove') && $search) {
q("delete from `term` where `uid` = %d and `type` = %d and `term` = '%s'",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
);
$search = '';
}
$srchurl = $a->query_string;
$srchurl = rtrim(preg_replace('/searchsave\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$hasq = ((strpos($srchurl,'?') !== false) ? true : false);
$srchurl = rtrim(preg_replace('/searchremove\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$hasq = ((strpos($srchurl,'?') !== false) ? true : false);
$srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
$hasq = ((strpos($srchurl,'?') !== false) ? true : false);
$o = '';
$r = q("select `tid`,`term` from `term` WHERE `uid` = %d and `type` = %d ",
intval(local_channel()),
intval(TERM_SAVEDSEARCH)
);
$saved = array();
if(count($r)) {
foreach($r as $rr) {
$saved[] = array(
'id' => $rr['tid'],
'term' => $rr['term'],
'dellink' => z_root() . '/' . $srchurl . (($hasq) ? '' : '?f=') . '&searchremove=1&search=' . urlencode($rr['term']),
'srchlink' => z_root() . '/' . $srchurl . (($hasq) ? '' : '?f=') . '&search=' . urlencode($rr['term']),
'displayterm' => htmlspecialchars($rr['term'], ENT_COMPAT,'UTF-8'),
'encodedterm' => urlencode($rr['term']),
'delete' => t('Remove term'),
'selected' => ($search==$rr['term']),
);
}
}
$tpl = get_markup_template("saved_searches.tpl");
$o = replace_macros($tpl, array(
'$title' => t('Saved Searches'),
'$add' => t('add'),
'$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), true),
'$saved' => $saved,
));
return $o;
}
function widget_filer($arr) {
if(! local_channel())
return '';
$a = get_app();
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();
$r = q("select distinct(term) from term where uid = %d and type = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
if(! $r)
return;
foreach($r as $rr)
$terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
return replace_macros(get_markup_template('fileas_widget.tpl'),array(
'$title' => t('Saved Folders'),
'$desc' => '',
'$sel_all' => (($selected == '') ? 'selected' : ''),
'$all' => t('Everything'),
'$terms' => $terms,
'$base' => z_root() . '/' . $a->cmd
));
}
function widget_archive($arr) {
$o = '';
$a = get_app();
if(! $a->profile_uid) {
return '';
}
$uid = $a->profile_uid;
if(! feature_enabled($uid,'archives'))
return '';
if(! perm_is_allowed($uid,get_observer_hash(),'view_stream'))
return '';
$wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0);
$style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select');
$showend = ((get_pconfig($uid,'system','archive_show_end_date')) ? true : false);
$mindate = get_pconfig($uid,'system','archive_mindate');
$visible_years = get_pconfig($uid,'system','archive_visible_years');
if(! $visible_years)
$visible_years = 5;
$url = z_root() . '/' . $a->cmd;
$ret = list_post_dates($uid,$wall,$mindate);
if(! count($ret))
return '';
$cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years;
$cutoff = ((array_key_exists($cutoff_year,$ret))? true : false);
$o = replace_macros(get_markup_template('posted_date_widget.tpl'),array(
'$title' => t('Archives'),
'$size' => $visible_years,
'$cutoff_year' => $cutoff_year,
'$cutoff' => $cutoff,
'$url' => $url,
'$style' => $style,
'$showend' => $showend,
'$dates' => $ret
));
return $o;
}
function widget_fullprofile($arr) {
$a = get_app();
if(! $a->profile['profile_uid'])
return;
$block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
return profile_sidebar($a->profile, $block);
}
function widget_categories($arr) {
$a = get_app();
if($a->profile['profile_uid'] && (! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_stream')))
return '';
$cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : '');
$srchurl = $a->query_string;
$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
return categories_widget($srchurl, $cat);
}
function widget_tagcloud_wall($arr) {
$a = get_app();
if((! $a->profile['profile_uid']) || (! $a->profile['channel_hash']))
return '';
if(! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_stream'))
return '';
$limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50);
if(feature_enabled($a->profile['profile_uid'], 'tagadelic'))
return wtagblock($a->profile['profile_uid'], $limit, $a->profile['channel_hash'], ITEM_WALL);
return '';
}
function widget_catcloud_wall($arr) {
$a = get_app();
if((! $a->profile['profile_uid']) || (! $a->profile['channel_hash']))
return '';
if(! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_stream'))
return '';
$limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50);
return catblock($a->profile['profile_uid'], $limit, $a->profile['channel_hash'], ITEM_WALL);
}
function widget_affinity($arr) {
if(! local_channel())
return '';
$cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : 0);
$cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : 99);
if(feature_enabled(local_channel(),'affinity')) {
$tpl = get_markup_template('main_slider.tpl');
$x = replace_macros($tpl,array(
'$val' => $cmin . ',' . $cmax,
'$refresh' => t('Refresh'),
'$me' => t('Me'),
'$intimate' => t('Best Friends'),
'$friends' => t('Friends'),
'$coworkers' => t('Co-workers'),
'$oldfriends' => t('Former Friends'),
'$acquaintances' => t('Acquaintances'),
'$world' => t('Everybody')
));
$arr = array('html' => $x);
call_hooks('main_slider',$arr);
return $arr['html'];
}
return '';
}
function widget_settings_menu($arr) {
if(! local_channel())
return;
$a = get_app();
$channel = $a->get_channel();
$abook_self_id = 0;
// Retrieve the 'self' address book entry for use in the auto-permissions link
$role = get_pconfig(local_channel(),'system','permissions_role');
$abk = q("select abook_id from abook where abook_channel = %d and ( abook_flags & %d )>0 limit 1",
intval(local_channel()),
intval(ABOOK_FLAG_SELF)
);
if($abk)
$abook_self_id = $abk[0]['abook_id'];
$tabs = array(
array(
'label' => t('Account settings'),
'url' => $a->get_baseurl(true).'/settings/account',
'selected' => ((argv(1) === 'account') ? 'active' : ''),
),
array(
'label' => t('Channel settings'),
'url' => $a->get_baseurl(true).'/settings/channel',
'selected' => ((argv(1) === 'channel') ? 'active' : ''),
),
array(
'label' => t('Additional features'),
'url' => $a->get_baseurl(true).'/settings/features',
'selected' => ((argv(1) === 'features') ? 'active' : ''),
),
array(
'label' => t('Feature/Addon settings'),
'url' => $a->get_baseurl(true).'/settings/featured',
'selected' => ((argv(1) === 'featured') ? 'active' : ''),
),
array(
'label' => t('Display settings'),
'url' => $a->get_baseurl(true).'/settings/display',
'selected' => ((argv(1) === 'display') ? 'active' : ''),
),
array(
'label' => t('Connected apps'),
'url' => $a->get_baseurl(true) . '/settings/oauth',
'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
),
array(
'label' => t('Export channel'),
'url' => $a->get_baseurl(true) . '/uexport',
'selected' => ''
),
);
if($role === false || $role === 'custom') {
$tabs[] = array(
'label' => t('Connection Default Permissions'),
'url' => $a->get_baseurl(true) . '/connedit/' . $abook_self_id,
'selected' => ''
);
}
if(feature_enabled(local_channel(),'premium_channel')) {
$tabs[] = array(
'label' => t('Premium Channel Settings'),
'url' => $a->get_baseurl(true) . '/connect/' . $channel['channel_address'],
'selected' => ''
);
}
if(feature_enabled(local_channel(),'channel_sources')) {
$tabs[] = array(
'label' => t('Channel Sources'),
'url' => $a->get_baseurl(true) . '/sources',
'selected' => ''
);
}
$tabtpl = get_markup_template("generic_links_widget.tpl");
return replace_macros($tabtpl, array(
'$title' => t('Settings'),
'$class' => 'settings-widget',
'$items' => $tabs,
));
}
function widget_mailmenu($arr) {
if (! local_channel())
return;
$a = get_app();
return replace_macros(get_markup_template('message_side.tpl'), array(
'$title' => t('Messages'),
'$tabs'=> array(),
'$check'=>array(
'label' => t('Check Mail'),
'url' => $a->get_baseurl(true) . '/message',
'sel' => (argv(1) == ''),
),
'$new'=>array(
'label' => t('New Message'),
'url' => $a->get_baseurl(true) . '/mail/new',
'sel'=> (argv(1) == 'new'),
)
));
}
function widget_design_tools($arr) {
$a = get_app();
// mod menu doesn't load a profile. For any modules which load a profile, check it.
// otherwise local_channel() is sufficient for permissions.
if($a->profile['profile_uid'])
if(($a->profile['profile_uid'] != local_channel()) && (! $a->is_sys))
return '';
if(! local_channel())
return '';
return design_tools();
}
function widget_findpeople($arr) {
return findpeople_widget();
}
function widget_photo_albums($arr) {
$a = get_app();
if(! $a->profile['profile_uid'])
return '';
$channelx = channelx_by_n($a->profile['profile_uid']);
if((! $channelx) || (! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_photos')))
return '';
require_once('include/photos.php');
return photos_album_widget($channelx, $a->get_observer());
}
function widget_vcard($arr) {
require_once ('include/Contact.php');
return vcard_from_xchan('', get_app()->get_observer());
}
/*
* The following directory widgets are only useful on the directory page
*/
function widget_dirsafemode($arr) {
return dir_safe_mode();
}
function widget_dirsort($arr) {
return dir_sort_links();
}
function widget_dirtags($arr) {
return dir_tagblock(z_root() . '/directory', null);
}
function widget_menu_preview($arr) {
if(! get_app()->data['menu_item'])
return;
require_once('include/menu.php');
return menu_render(get_app()->data['menu_item']);
}
function widget_chatroom_list($arr) {
$a = get_app();
require_once("include/chat.php");
$r = chatroom_list($a->profile['profile_uid']);
return replace_macros(get_markup_template('chatroomlist.tpl'), array(
'$header' => t('Chat Rooms'),
'$baseurl' => z_root(),
'$nickname' => $a->profile['channel_address'],
'$items' => $r,
));
}
function widget_bookmarkedchats($arr) {
$h = get_observer_hash();
if(! $h)
return;
$r = q("select xchat_url, xchat_desc from xchat where xchat_xchan = '%s' order by xchat_desc",
dbesc($h)
);
if($r) {
for($x = 0; $x < count($r); $x ++) {
$r[$x]['xchat_url'] = zid($r[$x]['xchat_url']);
}
}
return replace_macros(get_markup_template('bookmarkedchats.tpl'),array(
'$header' => t('Bookmarked Chatrooms'),
'$rooms' => $r
));
}
function widget_suggestedchats($arr) {
// probably should restrict this to your friends, but then the widget will only work
// if you are logged in locally.
$h = get_observer_hash();
if(! $h)
return;
$r = q("select xchat_url, xchat_desc, count(xchat_xchan) as total from xchat group by xchat_url, xchat_desc order by total desc, xchat_desc limit 24");
if($r) {
for($x = 0; $x < count($r); $x ++) {
$r[$x]['xchat_url'] = zid($r[$x]['xchat_url']);
}
}
return replace_macros(get_markup_template('bookmarkedchats.tpl'),array(
'$header' => t('Suggested Chatrooms'),
'$rooms' => $r
));
}
function widget_item($arr) {
// FIXME there is no $a here
$uid = $a->profile['profile_uid'];
if((! $uid) || (! $arr['mid']))
return '';
if(! perm_is_allowed($uid, get_observer_hash(), 'view_pages'))
return '';
require_once('include/security.php');
$sql_extra = item_permissions_sql($uid);
$r = q("select * from item where mid = '%s' and uid = %d and item_restrict = " . intval(ITEM_WEBPAGE) . " $sql_extra limit 1",
dbesc($arr['mid']),
intval($uid)
);
if(! $r)
return '';
xchan_query($r);
$r = fetch_post_tags($r, true);
$o = prepare_page($r[0]);
return $o;
}
function widget_clock($arr) {
$miltime = 0;
if(isset($arr['military']) && $arr['military'])
$miltime = 1;
$o = <<< EOT
<div class="widget">
<h3 class="clockface"></h3>
<script>
var timerID = null
var timerRunning = false
function stopclock(){
if(timerRunning)
clearTimeout(timerID)
timerRunning = false
}
function startclock(){
stopclock()
showtime()
}
function showtime(){
var now = new Date()
var hours = now.getHours()
var minutes = now.getMinutes()
var seconds = now.getSeconds()
var military = $miltime
var timeValue = ""
if(military)
timeValue = hours
else
timeValue = ((hours > 12) ? hours - 12 : hours)
timeValue += ((minutes < 10) ? ":0" : ":") + minutes
// timeValue += ((seconds < 10) ? ":0" : ":") + seconds
if(! military)
timeValue += (hours >= 12) ? " P.M." : " A.M."
$('.clockface').html(timeValue)
timerID = setTimeout("showtime()",1000)
timerRunning = true
}
$(document).ready(function() {
startclock();
});
</script>
</div>
EOT;
return $o;
}
/**
* @function widget_photo($arr)
* widget to display a single photo.
* @param array $arr;
* 'src' => URL of photo
* 'zrl' => true or false, use zid in url
* 'style' => CSS string
* URL must be an http or https URL
*/
function widget_photo($arr) {
$style = $zrl = false;
if(array_key_exists('src', $arr) && isset($arr['src']))
$url = $arr['src'];
if(strpos($url,'http') !== 0)
return '';
if(array_key_exists('style', $arr) && isset($arr['style']))
$style = $arr['style'];
// ensure they can't sneak in an eval(js) function
if(strpos($style,'(') !== false)
return '';
if(array_key_exists('zrl', $arr) && isset($arr['zrl']))
$zrl = (($arr['zrl']) ? true : false);
if($zrl)
$url = zid($url);
$o = '<div class="widget">';
$o .= '<img ' . (($zrl) ? ' class="zrl" ' : '')
. (($style) ? ' style="' . $style . '"' : '')
. ' src="' . $url . '" alt="' . t('photo/image') . '">';
$o .= '</div>';
return $o;
}
function widget_photo_rand($arr) {
require_once('include/photos.php');
$style = false;
if(array_key_exists('album', $arr) && isset($arr['album']))
$album = $arr['album'];
else
$album = '';
$channel_id = 0;
if(array_key_exists('channel_id', $arr) && intval($arr['channel_id']))
$channel_id = intval($arr['channel_id']);
if(! $channel_id)
$channel_id = get_app()->profile_uid;
if(! $channel_id)
return '';
$scale = ((array_key_exists('scale',$arr)) ? intval($arr['scale']) : 0);
$ret = photos_list_photos(array('channel_id' => $channel_id),get_app()->get_observer(),$album);
$filtered = array();
if($ret['success'] && $ret['photos'])
foreach($ret['photos'] as $p)
if($p['scale'] == $scale)
$filtered[] = $p['src'];
if($filtered) {
$e = mt_rand(0, count($filtered) - 1);
$url = $filtered[$e];
}
if(strpos($url, 'http') !== 0)
return '';
if(array_key_exists('style', $arr) && isset($arr['style']))
$style = $arr['style'];
// ensure they can't sneak in an eval(js) function
if(strpos($style,'(') !== false)
return '';
$url = zid($url);
$o = '<div class="widget">';
$o .= '<img class="zrl" '
. (($style) ? ' style="' . $style . '"' : '')
. ' src="' . $url . '" alt="' . t('photo/image') . '">';
$o .= '</div>';
return $o;
}
function widget_random_block($arr) {
$channel_id = 0;
if(array_key_exists('channel_id',$arr) && intval($arr['channel_id']))
$channel_id = intval($arr['channel_id']);
if(! $channel_id)
$channel_id = get_app()->profile_uid;
if(! $channel_id)
return '';
if(array_key_exists('contains',$arr))
$contains = $arr['contains'];
$o = '';
require_once('include/security.php');
$sql_options = item_permissions_sql($channel_id);
$randfunc = db_getfunc('RAND');
$r = q("select item.* from item left join item_id on item.id = item_id.iid
where item.uid = %d and sid like '%s' and service = 'BUILDBLOCK' and
item_restrict = %d $sql_options order by $randfunc limit 1",
intval($channel_id),
dbesc('%' . $contains . '%'),
intval(ITEM_BUILDBLOCK)
);
if($r) {
$o = '<div class="widget bblock">';
if($r[0]['title'])
$o .= '<h3>' . $r[0]['title'] . '</h3>';
$o .= prepare_text($r[0]['body'],$r[0]['mimetype']);
$o .= '</div>';
}
return $o;
}
function widget_rating($arr) {
$a = get_app();
if(! local_channel())
return;
$channel = $a->get_channel();
if($arr['target'])
$hash = $arr['target'];
else
$hash = $a->poi['xchan_hash'];
if(! $hash)
return;
if($hash == $channel['channel_hash'])
return;
head_add_js('ratings.js');
$o = '<div class="widget rateme">';
$o .= '<div class="rateme fakelink" onclick="doRatings(\'' . $hash . '\'); return false;"><i class="icon-pencil"></i> ' . t('Rate Me') . '</div></div>';
return $o;
}