2 rcs_id('$Id: RatingsDb.php,v 1.15 2007-05-29 16:56:54 rurban Exp $');
5 * @author: Dan Frankowski (wikilens group manager), Reini Urban (as plugin)
8 * - fix RATING_STORAGE = WIKIPAGE (dba, file)
10 * - finish mysuggest.c (external engine with data from mysql)
11 * - add the various show modes (esp. TopN queries in PHP)
15 dimension INT(4) NOT NULL,
16 raterpage INT(11) NOT NULL,
17 rateepage INT(11) NOT NULL,
18 ratingvalue FLOAT NOT NULL,
19 rateeversion INT(11) NOT NULL,
20 isPrivate ENUM('yes','no'),
21 tstamp TIMESTAMP(14) NOT NULL,
22 PRIMARY KEY (dimension, raterpage, rateepage)
26 // For other than SQL backends. dba + adodb SQL ratings are allowed but deprecated.
27 // We will probablöy drop this hack.
28 if (!defined('RATING_STORAGE'))
29 // for DATABASE_TYPE=dba and forced RATING_STORAGE=SQL we must use ADODB,
30 // but this is problematic.
31 define('RATING_STORAGE', $GLOBALS['request']->_dbi->_backend->isSQL() ? 'SQL' : 'WIKIPAGE');
32 //define('RATING_STORAGE','WIKIPAGE'); // not fully supported yet
34 // leave undefined for internal, slow php engine.
35 //if (!defined('RATING_EXTERNAL'))
36 // define('RATING_EXTERNAL',PHPWIKI_DIR . 'suggest.exe');
39 if (!defined('EXPLICIT_RATINGS_DIMENSION'))
40 define('EXPLICIT_RATINGS_DIMENSION', 0);
41 if (!defined('LIST_ITEMS_DIMENSION'))
42 define('LIST_ITEMS_DIMENSION', 1);
43 if (!defined('LIST_OWNER_DIMENSION'))
44 define('LIST_OWNER_DIMENSION', 2);
45 if (!defined('LIST_TYPE_DIMENSION'))
46 define('LIST_TYPE_DIMENSION', 3);
49 //TODO: split class into SQL and metadata backends
50 class RatingsDb extends WikiDB {
52 function RatingsDb() {
54 $this->_dbi = &$request->_dbi;
55 $this->_backend = &$this->_dbi->_backend;
56 $this->dimension = null;
57 if (RATING_STORAGE == 'SQL') {
58 if (isa($this->_backend, 'WikiDB_backend_PearDB')) {
59 $this->_sqlbackend = &$this->_backend;
60 $this->dbtype = "PearDB";
61 } elseif (isa($this->_backend, 'WikiDB_backend_ADODOB')) {
62 $this->_sqlbackend = &$this->_backend;
63 $this->dbtype = "ADODB";
65 include_once("lib/WikiDB/backend/ADODB.php");
66 // It is not possible to decouple a ref from the source again. (4.3.11)
67 // It replaced the main request backend. So we don't initialize _sqlbackend before.
68 //$this->_sqlbackend = clone($this->_backend);
69 $this->_sqlbackend = new WikiDB_backend_ADODB($GLOBALS['DBParams']);
70 $this->dbtype = "ADODB";
72 $this->iter_class = "WikiDB_backend_".$this->dbtype."_generic_iter";
74 extract($this->_sqlbackend->_table_names);
75 if (empty($rating_tbl)) {
76 $rating_tbl = (!empty($GLOBALS['DBParams']['prefix'])
77 ? $GLOBALS['DBParams']['prefix'] : '') . 'rating';
78 $this->_sqlbackend->_table_names['rating_tbl'] = $rating_tbl;
81 $this->iter_class = "WikiDB_Array_PageIterator";
85 // this is a singleton. It ensures there is only 1 ratingsDB.
86 function & getTheRatingsDb(){
87 static $_theRatingsDb;
89 if (!isset($_theRatingsDb)){
90 $_theRatingsDb = new RatingsDb();
92 //echo "rating db is $_theRatingsDb";
93 return $_theRatingsDb;
97 /// *************************************************************************************
99 // from Reini Urban's RateIt plugin
100 function addRating($rating, $userid, $pagename, $dimension) {
101 if (RATING_STORAGE == 'SQL') {
102 $page = $this->_dbi->getPage($pagename);
103 $current = $page->getCurrentRevision();
104 $rateeversion = $current->getVersion();
105 $this->sql_rate($userid, $pagename, $rateeversion, $dimension, $rating);
107 $this->metadata_set_rating($userid, $pagename, $dimension, $rating);
111 function deleteRating($userid=null, $pagename=null, $dimension=null) {
112 if (is_null($dimension)) $dimension = $this->dimension;
113 if (is_null($userid)) $userid = $this->userid;
114 if (is_null($pagename)) $pagename = $this->pagename;
115 if (RATING_STORAGE == 'SQL') {
116 $this->sql_delete_rating($userid, $pagename, $dimension);
118 $this->metadata_set_rating($userid, $pagename, $dimension, -1);
122 function getRating($userid=null, $pagename=null, $dimension=null) {
123 if (RATING_STORAGE == 'SQL') {
124 $ratings_iter = $this->sql_get_rating($dimension, $userid, $pagename);
125 if ($rating = $ratings_iter->next() and isset($rating['ratingvalue'])) {
126 return $rating['ratingvalue'];
130 return $this->metadata_get_rating($userid, $pagename, $dimension);
134 function getUsersRated($dimension=null, $orderby = null) {
135 if (is_null($dimension)) $dimension = $this->dimension;
136 //if (is_null($userid)) $userid = $this->userid;
137 //if (is_null($pagename)) $pagename = $this->pagename;
138 if (RATING_STORAGE == 'SQL') {
139 $ratings_iter = $this->sql_get_users_rated($dimension, $orderby);
140 if ($rating = $ratings_iter->next() and isset($rating['ratingvalue'])) {
141 return $rating['ratingvalue'];
145 return $this->metadata_get_users_rated($dimension, $orderby);
153 * @param dimension The rating dimension id.
156 * If this is null (or left off), the search for ratings
157 * is not restricted by dimension.
159 * @param rater The page id of the rater, i.e. page doing the rating.
160 * This is a Wiki page id, often of a user page.
163 * If this is null (or left off), the search for ratings
164 * is not restricted by rater.
165 * TODO: Support an array
167 * @param ratee The page id of the ratee, i.e. page being rated.
168 * Example: "DudeWheresMyCar"
170 * If this is null (or left off), the search for ratings
171 * is not restricted by ratee.
173 * @param orderby An order-by clause with fields and (optionally) ASC
175 * Example: "ratingvalue DESC"
177 * If this is null (or left off), the search for ratings
178 * has no guaranteed order
180 * @param pageinfo The type of page that has its info returned (i.e.,
181 * 'pagename', 'hits', and 'pagedata') in the rows.
184 * If this is null (or left off), the info returned
185 * is for the 'ratee' page (i.e., thing being rated).
187 * @return DB iterator with results
189 function get_rating($dimension=null, $rater=null, $ratee=null,
190 $orderby = null, $pageinfo = "ratee") {
191 if (RATING_STORAGE == 'SQL') {
192 $ratings_iter = $this->sql_get_rating($dimension, $rater, $pagename);
193 if ($rating = $ratings_iter->next() and isset($rating['ratingvalue'])) {
194 return $rating['ratingvalue'];
198 return $this->metadata_get_rating($rater, $pagename, $dimension);
201 return $this->_backend->get_rating($dimension, $rater, $ratee,
202 $orderby, $pageinfo);
206 function get_users_rated($dimension=null, $orderby = null) {
207 if (RATING_STORAGE == 'SQL') {
208 $ratings_iter = $this->sql_get_users_rated($dimension, $orderby);
209 if ($rating = $ratings_iter->next() and isset($rating['ratingvalue'])) {
210 return $rating['ratingvalue'];
214 return $this->metadata_get_users_rated($dimension, $orderby);
217 return $this->_backend->get_users_rated($dimension, $orderby);
222 * Like get_rating(), but return a WikiDB_PageIterator
225 function get_rating_page($dimension=null, $rater=null, $ratee=null,
226 $orderby = null, $pageinfo = "ratee") {
227 if (RATING_STORAGE == 'SQL') {
228 return $this->sql_get_rating($dimension, $rater, $ratee, $orderby, $pageinfo);
230 // empty dummy iterator
232 return new WikiDB_Array_PageIterator($pages);
239 * @param rater The page id of the rater, i.e. page doing the rating.
240 * This is a Wiki page id, often of a user page.
241 * @param ratee The page id of the ratee, i.e. page being rated.
242 * @param dimension The rating dimension id.
246 * @return true upon success
248 function delete_rating($rater, $ratee, $dimension) {
249 if (RATING_STORAGE == 'SQL') {
250 $this->sql_delete_rating($rater, $ratee, $dimension);
252 $this->metadata_set_rating($rater, $ratee, $dimension, -1);
259 * @param rater The page id of the rater, i.e. page doing the rating.
260 * This is a Wiki page id, often of a user page.
261 * @param ratee The page id of the ratee, i.e. page being rated.
262 * @param rateeversion The version of the ratee page.
263 * @param dimension The rating dimension id.
264 * @param rating The rating value (a float).
268 * @return true upon success
270 function rate($rater, $ratee, $rateeversion, $dimension, $rating) {
271 if (RATING_STORAGE == 'SQL') {
272 $page = $this->_dbi->getPage($pagename);
273 $current = $page->getCurrentRevision();
274 $rateeversion = $current->getVersion();
275 $this->sql_rate($userid, $pagename, $rateeversion, $dimension, $rating);
277 $this->metadata_set_rating($userid, $pagename, $dimension, $rating);
281 //function getUsersRated(){}
283 //*******************************************************************************
285 // Use wikilens/RatingsUser.php for the php methods.
288 // Currently we have to call the "suggest" CGI
289 // http://www-users.cs.umn.edu/~karypis/suggest/
290 // until we implement a simple recommendation engine.
291 // Note that "suggest" is only free for non-profit organizations.
292 // I am currently writing a binary CGI mysuggest using suggest, which loads
294 function getPrediction($userid=null, $pagename=null, $dimension=null) {
295 if (is_null($dimension)) $dimension = $this->dimension;
296 if (is_null($userid)) $userid = $this->userid;
297 if (is_null($pagename)) $pagename = $this->pagename;
299 if (RATING_STORAGE == 'SQL') {
300 $dbh = &$this->_sqlbackend;
301 if (isset($pagename))
302 $page = $dbh->_get_pageid($pagename);
306 $user = $dbh->_get_pageid($userid);
310 if (defined('RATING_EXTERNAL') and RATING_EXTERNAL) {
311 // how call mysuggest.exe? as CGI or natively
312 //$rating = HTML::Raw("<!--#include virtual=".RATING_ENGINE." -->");
313 $args = "-u$user -p$page -malpha"; // --top 10
314 if (isset($dimension))
315 $args .= " -d$dimension";
316 $rating = passthru(RATING_EXTERNAL . " $args");
318 $rating = $this->php_prediction($userid, $pagename, $dimension);
324 * TODO: slow item-based recommendation engine, similar to suggest RType=2.
325 * Only the SUGGEST_EstimateAlpha part
326 * Take wikilens/RatingsUser.php for the php methods.
328 function php_prediction($userid=null, $pagename=null, $dimension=null) {
329 if (is_null($dimension)) $dimension = $this->dimension;
330 if (is_null($userid)) $userid = $this->userid;
331 if (is_null($pagename)) $pagename = $this->pagename;
332 if (empty($this->buddies)) {
333 require_once("lib/wikilens/RatingsUser.php");
334 require_once("lib/wikilens/Buddy.php");
335 $user = RatingsUserFactory::getUser($userid);
336 $this->buddies = getBuddies($user, $GLOBALS['request']->_dbi);
338 return $user->knn_uu_predict($pagename, $this->buddies, $dimension);
341 function getNumUsers($pagename=null, $dimension=null) {
342 if (is_null($dimension)) $dimension = $this->dimension;
343 if (is_null($pagename)) $pagename = $this->pagename;
344 if (RATING_STORAGE == 'SQL') {
345 $ratings_iter = $this->sql_get_rating($dimension, null, $pagename,
347 return $ratings_iter->count();
349 if (!$pagename) return 0;
350 $page = $this->_dbi->getPage($pagename);
351 $data = $page->get('rating');
352 if (!empty($data[$dimension]))
353 return count($data[$dimension]);
359 // TODO: metadata method
360 function getAvg($pagename=null, $dimension=null) {
361 if (is_null($dimension)) $dimension = $this->dimension;
362 if (is_null($pagename)) $pagename = $this->pagename;
363 if (RATING_STORAGE == 'SQL') {
364 $dbi = &$this->_sqlbackend;
365 if (isset($pagename) || isset($dimension)) {
368 if (isset($pagename)) {
369 $raterid = $this->_sqlbackend->_get_pageid($pagename, true);
370 $where .= " raterpage=$raterid";
372 if (isset($dimension)) {
373 if (isset($pagename)) $where .= " AND";
374 $where .= " dimension=$dimension";
376 //$dbh = &$this->_dbi;
377 extract($dbi->_table_names);
378 $query = "SELECT AVG(ratingvalue) as avg"
379 . " FROM $rating_tbl r, $page_tbl p "
381 . " GROUP BY raterpage";
382 $result = $dbi->_dbh->query($query);
383 $iter = new $this->iter_class($this, $result);
384 $row = $iter->next();
387 if (!$pagename) return 0;
388 $page = $this->_dbi->getPage($pagename);
389 $data = $page->get('rating');
390 if (!empty($data[$dimension]))
391 // hash of userid => rating
392 return array_sum(array_values($data[$dimension])) / count($data[$dimension]);
397 //*******************************************************************************
402 * @param dimension The rating dimension id.
405 * If this is null (or left off), the search for ratings
406 * is not restricted by dimension.
408 * @param rater The page id of the rater, i.e. page doing the rating.
409 * This is a Wiki page id, often of a user page.
412 * If this is null (or left off), the search for ratings
413 * is not restricted by rater.
414 * TODO: Support an array
416 * @param ratee The page id of the ratee, i.e. page being rated.
417 * Example: "DudeWheresMyCar"
419 * If this is null (or left off), the search for ratings
420 * is not restricted by ratee.
421 * TODO: Support an array
423 * @param orderby An order-by clause with fields and (optionally) ASC
425 * Example: "ratingvalue DESC"
427 * If this is null (or left off), the search for ratings
428 * has no guaranteed order
430 * @param pageinfo The type of page that has its info returned (i.e.,
431 * 'pagename', 'hits', and 'pagedata') in the rows.
434 * If this is null (or left off), the info returned
435 * is for the 'ratee' page (i.e., thing being rated).
437 * @return DB iterator with results
439 function sql_get_rating($dimension=null, $rater=null, $ratee=null,
440 $orderby=null, $pageinfo = "ratee") {
441 if (empty($dimension)) $dimension=null;
442 $result = $this->_sql_get_rating_result($dimension, $rater, $ratee, $orderby, $pageinfo);
443 return new $this->iter_class($this, $result);
446 function sql_get_users_rated($dimension=null, $orderby=null) {
447 if (empty($dimension)) $dimension=null;
448 $result = $this->_sql_get_rating_result($dimension, null, null, $orderby, "rater");
449 return new $this->iter_class($this, $result);
454 * @return result ressource, suitable to the iterator
456 function _sql_get_rating_result($dimension=null, $rater=null, $ratee=null,
457 $orderby=null, $pageinfo = "ratee") {
458 // pageinfo must be 'rater' or 'ratee'
459 if (($pageinfo != "ratee") && ($pageinfo != "rater"))
461 $dbi = &$this->_sqlbackend;
464 //$dbh = &$this->_dbi;
465 extract($dbi->_table_names);
466 $where = "WHERE r." . $pageinfo . "page = p.id";
467 if (isset($dimension)) {
468 $where .= " AND dimension=$dimension";
471 $raterid = $dbi->_get_pageid($rater, true);
472 $where .= " AND raterpage=$raterid";
475 if(is_array($ratee)){
477 for($i = 0; $i < count($ratee); $i++){
478 $rateeid = $dbi->_get_pageid($ratee[$i], true);
479 $where .= "rateepage=$rateeid";
480 if($i != (count($ratee) - 1)){
486 $rateeid = $dbi->_get_pageid($ratee, true);
487 $where .= " AND rateepage=$rateeid";
491 if (isset($orderby)) {
492 $orderbyStr = " ORDER BY " . $orderby;
494 if (isset($rater) or isset($ratee)) $what = '*';
495 // same as _get_users_rated_result()
496 else $what = 'DISTINCT p.pagename';
498 $query = "SELECT $what"
499 . " FROM $rating_tbl r, $page_tbl p "
502 $result = $dbi->query($query);
509 * @param rater The page id of the rater, i.e. page doing the rating.
510 * This is a Wiki page id, often of a user page.
511 * @param ratee The page id of the ratee, i.e. page being rated.
512 * @param dimension The rating dimension id.
516 * @return true upon success
518 function sql_delete_rating($rater, $ratee, $dimension) {
519 //$dbh = &$this->_dbi;
520 $dbi = &$this->_sqlbackend;
521 extract($dbi->_table_names);
524 $raterid = $dbi->_get_pageid($rater, true);
525 $rateeid = $dbi->_get_pageid($ratee, true);
526 $where = "WHERE raterpage=$raterid and rateepage=$rateeid";
527 if (isset($dimension)) {
528 $where .= " AND dimension=$dimension";
530 $dbi->_dbh->query("DELETE FROM $rating_tbl $where");
538 * @param rater The page id of the rater, i.e. page doing the rating.
539 * This is a Wiki page id, often of a user page.
540 * @param ratee The page id of the ratee, i.e. page being rated.
541 * @param rateeversion The version of the ratee page.
542 * @param dimension The rating dimension id.
543 * @param rating The rating value (a float).
547 * @return true upon success
549 // ($this->userid, $this->pagename, $page->version, $this->dimension, $rating);
550 function sql_rate($rater, $ratee, $rateeversion, $dimension, $rating) {
551 $dbi = &$this->_sqlbackend;
552 extract($dbi->_table_names);
553 if (empty($rating_tbl))
554 $rating_tbl = $this->_dbi->getParam('prefix') . 'rating';
557 $raterid = $dbi->_get_pageid($rater, true);
558 $rateeid = $dbi->_get_pageid($ratee, true);
561 //mysql optimize: REPLACE if raterpage and rateepage are keys
562 $dbi->_dbh->query("DELETE from $rating_tbl WHERE dimension=$dimension AND raterpage=$raterid AND rateepage=$rateeid");
563 $where = "WHERE raterpage='$raterid' AND rateepage='$rateeid'";
564 $insert = "INSERT INTO $rating_tbl (dimension, raterpage, rateepage, ratingvalue, rateeversion)"
565 ." VALUES ('$dimension', $raterid, $rateeid, '$rating', '$rateeversion')";
566 $dbi->_dbh->query($insert);
572 function metadata_get_rating($userid, $pagename, $dimension) {
573 if (!$pagename) return false;
574 $page = $this->_dbi->getPage($pagename);
575 $data = $page->get('rating');
576 if (!empty($data[$dimension][$userid]))
577 return (float)$data[$dimension][$userid];
582 function metadata_set_rating($userid, $pagename, $dimension, $rating = -1) {
583 if (!$pagename) return false;
584 $page = $this->_dbi->getPage($pagename);
585 $data = $page->get('rating');
587 unset($data[$dimension][$userid]);
589 if (empty($data[$dimension][$userid]))
590 $data[$dimension] = array($userid => (float)$rating);
592 $data[$dimension][$userid] = $rating;
594 $page->set('rating',$data);
600 class RatingsDB_backend_PearDB
601 extends WikiDB_backend_PearDB {
602 function get_rating($dimension=null, $rater=null, $ratee=null,
603 $orderby=null, $pageinfo = "ratee") {
604 $result = $this->_get_rating_result(
605 $dimension, $rater, $ratee, $orderby, $pageinfo);
606 return new WikiDB_backend_PearDB_generic_iter($this, $result);
609 function get_users_rated($dimension=null, $orderby=null) {
610 $result = $this->_get_users_rated_result(
611 $dimension, $orderby);
612 return new WikiDB_backend_PearDB_generic_iter($this, $result);
615 function get_rating_page($dimension=null, $rater=null, $ratee=null,
616 $orderby=null, $pageinfo = "ratee") {
617 $result = $this->_get_rating_result(
618 $dimension, $rater, $ratee, $orderby, $pageinfo);
619 return new WikiDB_backend_PearDB_iter($this, $result);
622 function _get_rating_result($dimension=null, $rater=null, $ratee=null,
623 $orderby=null, $pageinfo = "ratee") {
624 // pageinfo must be 'rater' or 'ratee'
625 if (($pageinfo != "ratee") && ($pageinfo != "rater"))
629 extract($this->_table_names);
631 $where = "WHERE r." . $pageinfo . "page = p.id";
632 if (isset($dimension)) {
633 $where .= " AND dimension=$dimension";
636 $raterid = $this->_get_pageid($rater, true);
637 $where .= " AND raterpage=$raterid";
640 if(is_array($ratee)){
642 for($i = 0; $i < count($ratee); $i++){
643 $rateeid = $this->_get_pageid($ratee[$i], true);
644 $where .= "rateepage=$rateeid";
645 if($i != (count($ratee) - 1)){
651 $rateeid = $this->_get_pageid($ratee, true);
652 $where .= " AND rateepage=$rateeid";
657 if (isset($orderby)) {
658 $orderbyStr = " ORDER BY " . $orderby;
662 . " FROM $rating_tbl r, $page_tbl p "
666 $result = $dbh->query($query);
671 function _get_users_rated_result($dimension=null, $orderby=null) {
673 extract($this->_table_names);
675 $where = "WHERE p.id=r.raterpage";
676 if (isset($dimension)) {
677 $where .= " AND dimension=$dimension";
680 if (isset($orderby)) {
681 $orderbyStr = " ORDER BY " . $orderby;
684 $query = "SELECT DISTINCT p.pagename"
685 . " FROM $rating_tbl r, $page_tbl p "
689 $result = $dbh->query($query);
693 function delete_rating($rater, $ratee, $dimension) {
695 extract($this->_table_names);
698 $raterid = $this->_get_pageid($rater, true);
699 $rateeid = $this->_get_pageid($ratee, true);
701 $dbh->query("DELETE FROM $rating_tbl WHERE raterpage=$raterid and rateepage=$rateeid and dimension=$dimension");
706 function rate($rater, $ratee, $rateeversion, $dimension, $rating, $isPrivate = 'no') {
708 extract($this->_table_names);
711 $raterid = $this->_get_pageid($rater, true);
712 $rateeid = $this->_get_pageid($ratee, true);
714 $dbh->query("DELETE FROM $rating_tbl WHERE raterpage=$raterid and rateepage=$rateeid and dimension=$dimension and isPrivate='$isPrivate'");
715 // NOTE: Leave tstamp off the insert, and MySQL automatically updates it
716 $dbh->query("INSERT INTO $rating_tbl (dimension, raterpage, rateepage, ratingvalue, rateeversion, isPrivate) VALUES ($dimension, $raterid, $rateeid, $rating, $rateeversion, '$isPrivate')");
723 // $Log: not supported by cvs2svn $
724 // Revision 1.14 2007/01/21 23:16:29 rurban
725 // Fix dba with RATING_STORAGE=SQL
727 // Revision 1.13 2005/10/10 19:51:41 rurban
728 // fix aesthetic issues by John Stevens
730 // Revision 1.12 2004/11/15 16:00:02 rurban
731 // enable RateIt imgPrefix: '' or 'Star' or 'BStar',
732 // enable blue prediction icons,
733 // enable buddy predictions.
735 // Revision 1.11 2004/11/01 10:44:00 rurban
736 // seperate PassUser methods into seperate dir (memory usage)
737 // fix WikiUser (old) overlarge data session
738 // remove wikidb arg from various page class methods, use global ->_dbi instead
741 // Revision 1.10 2004/10/05 17:00:04 rurban
742 // support paging for simple lists
743 // fix RatingDb sql backend.
744 // remove pages from AllPages (this is ListPages then)
746 // Revision 1.9 2004/10/05 00:33:44 rurban
747 // intermediate fix for non-sql WikiDB and SQL rating
749 // Revision 1.8 2004/07/20 18:00:50 dfrankow
750 // Add EXPLICIT_RATINGS_DIMENSION constant. More dimensions on the way
753 // Fix delete_rating().
755 // Revision 1.7 2004/07/08 19:14:57 rurban
756 // more metadata fixes
758 // Revision 1.6 2004/07/08 19:04:45 rurban
759 // more unittest fixes (file backend, metadata RatingsDb)
761 // Revision 1.5 2004/07/08 13:50:33 rurban
762 // various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
764 // Revision 1.4 2004/07/07 19:47:36 dfrankow
765 // Fixes to get PreferencesApp to work-- thanks syilek
767 // Revision 1.3 2004/06/30 20:05:36 dfrankow
768 // + Add getTheRatingsDb() singleton.
769 // + Remove defaulting of dimension, userid, pagename in getRating--
771 // + Fix typo in get_rating.
772 // + Fix _sql_get_rating_result
773 // + Fix sql_rate(). It's now not transactionally safe yet, but at least it
776 // Revision 1.2 2004/06/19 10:22:41 rurban
777 // outcomment the pear specific methods to let all pages load
779 // Revision 1.1 2004/06/18 14:42:17 rurban
780 // added wikilens libs (not yet merged good enough, some work for DanFr)
787 // c-hanging-comment-ender-p: nil
788 // indent-tabs-mode: nil