diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/comanche.php | 77 | ||||
-rw-r--r-- | include/dir_fns.php | 3 | ||||
-rw-r--r-- | include/enotify.php | 6 | ||||
-rw-r--r-- | include/identity.php | 2 | ||||
-rwxr-xr-x | include/items.php | 50 | ||||
-rw-r--r-- | include/menu.php | 3 | ||||
-rw-r--r-- | include/message.php | 2 | ||||
-rw-r--r-- | include/nav.php | 39 | ||||
-rwxr-xr-x | include/oembed.php | 11 | ||||
-rw-r--r-- | include/poller.php | 11 | ||||
-rw-r--r-- | include/socgraph.php | 29 | ||||
-rwxr-xr-x | include/text.php | 12 | ||||
-rw-r--r-- | include/widgets.php | 61 | ||||
-rw-r--r-- | include/zot.php | 37 |
14 files changed, 265 insertions, 78 deletions
diff --git a/include/comanche.php b/include/comanche.php index 7d7e0e70c..13146ded4 100644 --- a/include/comanche.php +++ b/include/comanche.php @@ -57,6 +57,23 @@ function comanche_parser(&$a,$s) { if($cnt) $a->page['template'] = trim($matches[1]); + $cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches); + if($cnt) { + $a->page['template'] = trim($matches[2]); + $a->page['template_style'] = trim($matches[2]) . '_' . $matches[1]; + } + + $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches); + if($cnt) { + $a->page['template'] = trim($matches[1]); + } + + $cnt = preg_match("/\[theme=(.*?)\](.*?)\[\/theme\]/ism", $s, $matches); + if($cnt) { + $a->layout['schema'] = trim($matches[1]); + $a->layout['theme'] = trim($matches[2]); + } + $cnt = preg_match("/\[theme\](.*?)\[\/theme\]/ism", $s, $matches); if($cnt) $a->layout['theme'] = trim($matches[1]); @@ -79,10 +96,12 @@ function comanche_parser(&$a,$s) { } -function comanche_menu($name) { - $a = get_app(); - $m = menu_fetch($name,$a->profile['profile_uid'],get_observer_hash()); - return menu_render($m); +function comanche_menu($name,$class = '') { + $channel_id = comanche_get_channel_id(); + if($channel_id) { + $m = menu_fetch($name,$channel_id,get_observer_hash()); + return menu_render($m,$class); + } } function comanche_replace_region($match) { @@ -92,20 +111,37 @@ function comanche_replace_region($match) { } } +/** + * @function comanche_get_channel_id() + * Returns the channel_id of the profile owner of the page, or the local_user if there is no profile owner. + * Otherwise returns 0 + */ + +function comanche_get_channel_id() { + $channel_id = ((is_array(get_app()->profile)) ? get_app()->profile['profile_uid'] : 0); + if((! $channel_id) && (local_user())) + $channel_id = local_user(); + return $channel_id; +} + function comanche_block($name) { + + $channel_id = comanche_get_channel_id(); - $o = ''; - $r = q("select * from item inner join item_id on iid = item.id and item_id.uid = item.uid and item.uid = %d and service = 'BUILDBLOCK' and sid = '%s' limit 1", - intval(get_app()->profile['profile_uid']), - dbesc($name) - ); - 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>'; + if($channel_id) { + $o = ''; + $r = q("select * from item inner join item_id on iid = item.id and item_id.uid = item.uid and item.uid = %d and service = 'BUILDBLOCK' and sid = '%s' limit 1", + intval($channel_id), + dbesc($name) + ); + 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; } @@ -152,13 +188,22 @@ function comanche_widget($name,$text) { function comanche_region(&$a,$s) { - $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); if($cnt) { foreach($matches as $mtch) { $s = str_replace($mtch[0],comanche_menu(trim($mtch[1])),$s); } } + + // menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu] + // allows different menu renderings to be applied + + $cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + $s = str_replace($mtch[0],comanche_menu(trim($mtch[2]),$mtch[1]),$s); + } + } $cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); if($cnt) { foreach($matches as $mtch) { diff --git a/include/dir_fns.php b/include/dir_fns.php index c2e614831..aeee8492f 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -101,6 +101,9 @@ function sync_directories($dirmode) { $ud_flags = 0; if(is_array($t['flags']) && in_array('deleted',$t['flags'])) $ud_flags |= UPDATE_FLAGS_DELETED; + if(is_array($t['flags']) && in_array('forced',$t['flags'])) + $ud_flags |= UPDATE_FLAGS_FORCED; + $z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' ) ", dbesc($t['hash']), diff --git a/include/enotify.php b/include/enotify.php index e0991257f..036d5275e 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -384,6 +384,12 @@ function notification($params) { $itemlink = $a->get_baseurl() . '/notify/view/' . $notify_id; $msg = str_replace('$itemlink',$itemlink,$epreamble); + + // wretched hack, but we don't want to duplicate all the preamble variations and we also don't want to screw up a translation + + if(($a->language === 'en' || (! $a->language)) && strpos($msg,', ')) + $msg = substr($msg,strpos($msg,', ')+1); + $r = q("update notify set msg = '%s' where id = %d and uid = %d limit 1", dbesc($msg), intval($notify_id), diff --git a/include/identity.php b/include/identity.php index 2e611625a..93174031c 100644 --- a/include/identity.php +++ b/include/identity.php @@ -1112,8 +1112,6 @@ function get_theme_uid() { if(local_user()) { if((get_pconfig(local_user(),'system','always_my_theme')) || (! $uid)) return local_user(); - if(! $uid) - return local_user(); } if(! $uid) { $x = get_sys_channel(); diff --git a/include/items.php b/include/items.php index d380a7939..6ff984370 100755 --- a/include/items.php +++ b/include/items.php @@ -3409,8 +3409,11 @@ function item_expire($uid,$days) { // $expire_network_only = save your own wall posts // and just expire conversations started by others + // do not enable this until we can pass bulk delete messages through zot + // $expire_network_only = get_pconfig($uid,'expire','network_only'); + + $expire_network_only = 1; - $expire_network_only = get_pconfig($uid,'expire','network_only'); $sql_extra = ((intval($expire_network_only)) ? " AND not (item_flags & " . intval(ITEM_WALL) . ") " : ""); $r = q("SELECT * FROM `item` @@ -3418,14 +3421,11 @@ function item_expire($uid,$days) { AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY AND `id` = `parent` $sql_extra - AND NOT (item_restrict & %d ) - AND NOT (item_restrict & %d ) - AND NOT (item_restrict & %d ) ", + AND NOT ( item_flags & %d ) + AND (item_restrict = 0 ) ", intval($uid), intval($days), - intval(ITEM_DELETED), - intval(ITEM_WEBPAGE), - intval(ITEM_BUILDBLOCK) + intval(ITEM_RETAINED) ); if(! $r) @@ -3433,44 +3433,40 @@ function item_expire($uid,$days) { $r = fetch_post_tags($r,true); - $expire_items = get_pconfig($uid, 'expire','items'); - $expire_items = (($expire_items===false)?1:intval($expire_items)); // default if not set: 1 - - $expire_notes = get_pconfig($uid, 'expire','notes'); - $expire_notes = (($expire_notes===false)?1:intval($expire_notes)); // default if not set: 1 - - $expire_starred = get_pconfig($uid, 'expire','starred'); - $expire_starred = (($expire_starred===false)?1:intval($expire_starred)); // default if not set: 1 - - $expire_photos = get_pconfig($uid, 'expire','photos'); - $expire_photos = (($expire_photos===false)?0:intval($expire_photos)); // default if not set: 0 - - logger('expire: # items=' . count($r). "; expire items: $expire_items, expire notes: $expire_notes, expire starred: $expire_starred, expire photos: $expire_photos"); - foreach($r as $item) { - - // don't expire filed items $terms = get_terms_oftype($item['term'],TERM_FILE); - if($terms) + if($terms) { + retain_item($item['id']); continue; + } // Only expire posts, not photos and photo comments - if($expire_photos==0 && ($item['resource_type'] === 'photo')) + if($item['resource_type'] === 'photo') { + retain_item($item['id']); continue; - if($expire_starred==0 && ($item['item_flags'] & ITEM_STARRED)) + } + if($item['item_flags'] & ITEM_STARRED) { + retain_item($item['id']); continue; + } drop_item($item['id'],false); } - proc_run('php',"include/notifier.php","expire","$uid"); +// proc_run('php',"include/notifier.php","expire","$uid"); } +function retain_item($id) { + $r = q("update item set item_flags = (item_flags | %d ) where id = %d limit 1", + intval(ITEM_RETAINED), + intval($id) + ); +} function drop_items($items) { $uid = 0; diff --git a/include/menu.php b/include/menu.php index 2f1719d0b..4b0a11f10 100644 --- a/include/menu.php +++ b/include/menu.php @@ -24,7 +24,7 @@ function menu_fetch($name,$uid,$observer_xchan) { return null; } -function menu_render($menu, $edit = false) { +function menu_render($menu, $class='', $edit = false) { if(! $menu) return ''; @@ -38,6 +38,7 @@ function menu_render($menu, $edit = false) { return replace_macros(get_markup_template('usermenu.tpl'),array( '$menu' => $menu['menu'], + '$class' => $class, '$edit' => (($edit) ? t("Edit") : ''), '$items' => $menu['items'] )); diff --git a/include/message.php b/include/message.php index a95021583..607166ec9 100644 --- a/include/message.php +++ b/include/message.php @@ -76,7 +76,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $match = null; $images = null; - if(preg_match_all("/\[img\](.*?)\[\/img\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match)) + if(preg_match_all("/\[zmg\](.*?)\[\/zmg\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match)) $images = $match[1]; $match = false; diff --git a/include/nav.php b/include/nav.php index dd15ff411..ab0eaa855 100644 --- a/include/nav.php +++ b/include/nav.php @@ -8,12 +8,10 @@ function nav(&$a) { * */ - $ssl_state = ((local_user()) ? true : false); - if(!(x($a->page,'nav'))) $a->page['nav'] = ''; - $base = $a->get_baseurl($ssl_state); + $base = z_root(); $a->page['htmlhead'] .= <<< EOT <script>$(document).ready(function() { @@ -33,18 +31,6 @@ EOT; - /** - * Placeholder div for popup panel - */ - - /** - * - * Our network is distributed, and as you visit friends some of the - * sites look exactly the same - it isn't always easy to know where you are. - * Display the current site location as a navigation aid. - * - */ - if(local_user()) { $channel = $a->get_channel(); $observer = $a->get_observer(); @@ -58,6 +44,26 @@ EOT; $sitelocation = (($myident) ? $myident : $a->get_hostname()); + + /** + * + * Provide a banner/logo/whatever + * + */ + + $banner = get_config('system','banner'); + + if($banner === false) + $banner = get_config('system','sitename'); + + $a->page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$sitelocation' => $sitelocation, + '$langselector' => ((get_config('system','select_language')) ? lang_selector() : ''), + '$banner' => $banner + )); + + // nav links: array of array('href', 'text', 'extra css classes', 'title') $nav = Array(); @@ -128,7 +134,7 @@ EOT; if(($a->config['system']['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) $nav['register'] = array('register',t('Register'), "", t('Create an account')); - $help_url = $a->get_baseurl($ssl_state) . '/help'; + $help_url = z_root() . '/help?f=&cmd=' . $a->cmd; if(! get_config('system','hide_help')) $nav['help'] = array($help_url, t('Help'), "", t('Help and documentation')); @@ -209,7 +215,6 @@ EOT; $a->page['nav'] .= replace_macros($tpl, array( '$baseurl' => $a->get_baseurl(), - '$langselector' => ((get_config('system','select_language')) ? lang_selector() : ''), '$sitelocation' => $sitelocation, '$nav' => $x['nav'], '$banner' => $banner, diff --git a/include/oembed.php b/include/oembed.php index d8671a752..57631b051 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -14,6 +14,10 @@ function oembed_fetch_url($embedurl){ $txt = Cache::get($a->videowidth . $embedurl); + if(strstr($txt,'youtu')) { + $txt = str_replace('http:','https:',$txt); + } + // These media files should now be caught in bbcode.php // left here as a fallback in case this is called from another source @@ -99,6 +103,13 @@ function oembed_format_object($j){ $th=120; $tw = $th*$tr; $tpl=get_markup_template('oembed_video.tpl'); + if(strstr($embedurl,'youtu')) { + $embedurl = str_replace('http:','https:',$embedurl); + $j->thumbnail_url = str_replace('http:','https:', $j->thumbnail_url); + $jhtml = str_replace('http:','https:', $jhtml); + $j->html = str_replace('http:','https:', $j->html); + + } $ret.=replace_macros($tpl, array( '$baseurl' => $a->get_baseurl(), '$embedurl'=>$embedurl, diff --git a/include/poller.php b/include/poller.php index 1c6f68eab..649da30f6 100644 --- a/include/poller.php +++ b/include/poller.php @@ -76,7 +76,7 @@ function poller_run($argv, $argc){ intval($rr['id']) ); if($x) { - proc_run('php','include/notifer.php','wall-new',$rr['id']); + proc_run('php','include/notifier.php','wall-new',$rr['id']); } } } @@ -96,9 +96,13 @@ function poller_run($argv, $argc){ $dirmode = get_config('system','directory_mode'); + /** + * Cron Daily + * + * Actions in the following block are executed once per day, not on every poller run + * + */ - // Actions in the following block are executed once per day, not on every poller run - if($d2 != intval($d1)) { // expire any read notifications over a month old @@ -121,6 +125,7 @@ function poller_run($argv, $argc){ set_config('system','last_expire_day',$d2); + proc_run('php','include/expire.php'); proc_run('php','include/cli_suggest.php'); } diff --git a/include/socgraph.php b/include/socgraph.php index 0e91eba60..10d52da66 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -64,6 +64,35 @@ function poco_load($xchan = '',$url = null) { logger('poco_load: ' . print_r($j,true),LOGGER_DATA); + if($xchan) { + if(array_key_exists('chatrooms',$j) && is_array($j['chatrooms'])) { + foreach($j['chatrooms'] as $room) { + $r = q("select * from xchat where xchat_url = '%s' and xchat_xchan = '%s' limit 1", + dbesc($room['url']), + dbesc($xchan) + ); + if($r) { + q("update xchat set xchat_edited = '%s' where xchat_id = %d limit 1", + dbesc(datetime_convert()), + intval($r[0]['xchat_id']) + ); + } + else { + $x = q("insert into xchat ( xchat_url, xchat_desc, xchat_xchan, xchat_edited ) + values ( '%s', '%s', '%s', '%s' ) ", + dbesc(escape_tags($room['url'])), + dbesc(escape_tags($room['desc'])), + dbesc($xchan), + dbesc(datetime_convert()) + ); + } + } + } + q("delete from xchat where xchat_edited < UTC_TIMESTAMP() - INTERVAL 7 DAY and xchat_xchan = '%s' ", + dbesc($xchan) + ); + } + if(! ((x($j,'entry')) && (is_array($j['entry'])))) { logger('poco_load: no entries'); return; diff --git a/include/text.php b/include/text.php index dfd35c769..839e63f5e 100755 --- a/include/text.php +++ b/include/text.php @@ -665,8 +665,11 @@ function contact_block() { if((! is_array($a->profile)) || ($a->profile['hide_friends'])) return $o; - $r = q("SELECT COUNT(abook_id) AS total FROM abook WHERE abook_channel = %d and abook_flags = 0", - intval($a->profile['uid']) + $r = q("SELECT COUNT(abook_id) AS total FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_flags = 0 and not (xchan_flags & %d) and not (xchan_flags & %d) and not (xchan_flags & %d)", + intval($a->profile['uid']), + intval(XCHAN_FLAGS_HIDDEN), + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_DELETED) ); if(count($r)) { $total = intval($r[0]['total']); @@ -677,8 +680,11 @@ function contact_block() { } else { - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d AND abook_flags = 0 ORDER BY RAND() LIMIT %d", + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d AND abook_flags = 0 and not (xchan_flags & %d ) and not (xchan_flags & %d ) and not (xchan_flags & %d ) ORDER BY RAND() LIMIT %d", intval($a->profile['uid']), + intval(XCHAN_FLAGS_HIDDEN), + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_DELETED), intval($shown) ); diff --git a/include/widgets.php b/include/widgets.php index 4a5ae9de7..8d8eef160 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -589,3 +589,64 @@ function widget_chatroom_list($arr) { )); } +function widget_bookmarkedchats($arr) { + $h = get_observer_hash(); + if(! $h) + return; + $r = q("select * from xchat where xchat_xchan = '%s' group by xchat_url order by xchat_desc", + dbesc($h) + ); + + 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 *, count(xchat_url) as total from xchat group by xchat_url order by total desc, xchat_desc limit 24"); + + 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) { + $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; + +}
\ No newline at end of file diff --git a/include/zot.php b/include/zot.php index d7d7eb419..e80dabed9 100644 --- a/include/zot.php +++ b/include/zot.php @@ -305,7 +305,7 @@ function zot_refresh($them,$channel = null, $force = false) { return false; } - $x = import_xchan($j,(($force) ? (-1) : 1)); + $x = import_xchan($j,(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); if(! $x['success']) return false; @@ -330,8 +330,15 @@ function zot_refresh($them,$channel = null, $force = false) { else $permissions = $j['permissions']; + $connected_set = false; + if($permissions && is_array($permissions)) { foreach($permissions as $k => $v) { + // The connected permission means you are in their address book + if($k === 'connected') { + $connected_set = intval($v); + continue; + } if($v) { $their_perms = $their_perms | intval($global_perms[$k][1]); } @@ -353,6 +360,20 @@ function zot_refresh($them,$channel = null, $force = false) { intval($channel['channel_id']), intval(ABOOK_FLAG_SELF) ); + if($connected_set === 0) { + + // if they are in your address book but you aren't in theirs, mark their address book entry hidden. + + $y1 = q("update abook set abook_flags = (abook_flags | %d) + where abook_xchan = '%s' and abook_channel = %d + and not (abook_flags & %d) limit 1", + intval(ABOOK_FLAG_HIDDEN), + dbesc($x['hash']), + intval($channel['channel_id']), + intval(ABOOK_FLAG_SELF) + ); + } + if(! $y) logger('abook update failed'); else { @@ -517,14 +538,14 @@ function zot_register_hub($arr) { /** - * @function import_xchan($arr,$ud_flags = 1) + * @function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) * Takes an associative array of a fetched discovery packet and updates * all internal data structures which need to be updated as a result. * * @param array $arr => json_decoded discovery packet * @param int $ud_flags - * Determines whether to create a directory update record if any changes occur, default 1 or true - * $ud_flags = (-1) indicates a forced refresh where we unconditionally create a directory update record + * Determines whether to create a directory update record if any changes occur, default is UPDATE_FLAGS_UPDATED (true) + * $ud_flags = UPDATE_FLAGS_FORCED indicates a forced refresh where we unconditionally create a directory update record * this typically occurs once a month for each channel as part of a scheduled ping to notify the directory * that the channel still exists * @@ -532,7 +553,7 @@ function zot_register_hub($arr) { * 'message' (optional error string only if success is false) */ -function import_xchan($arr,$ud_flags = 1) { +function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) { call_hooks('import_xchan', $arr); @@ -891,7 +912,7 @@ function import_xchan($arr,$ud_flags = 1) { } } - if(($changed) || ($ud_flags == (-1))) { + if(($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { $guid = random_string() . '@' . get_app()->get_hostname(); update_modtime($xchan_hash,$guid,$arr['address'],$ud_flags); logger('import_xchan: changed: ' . $what,LOGGER_DEBUG); @@ -1623,7 +1644,7 @@ function process_profile_delivery($sender,$arr,$deliveries) { dbesc($sender['hash']) ); if($r) - import_directory_profile($sender['hash'],$arr,$r[0]['xchan_addr'], 1, 0); + import_directory_profile($sender['hash'],$arr,$r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); } @@ -1634,7 +1655,7 @@ function process_profile_delivery($sender,$arr,$deliveries) { * */ -function import_directory_profile($hash,$profile,$addr,$ud_flags = 1, $suppress_update = 0) { +function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) { logger('import_directory_profile', LOGGER_DEBUG); if(! $hash) |