mirror of
https://github.com/UnickSoft/graphonline.git
synced 2025-07-01 15:26:12 +00:00
545 lines
18 KiB
PHP
Executable File
545 lines
18 KiB
PHP
Executable File
<?php if (!defined('PmWiki')) exit();
|
|
/* Copyright 2005-2010 Patrick R. Michaud (pmichaud@pobox.com)
|
|
This file is part of PmWiki; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published
|
|
by the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version. See pmwiki.php for full details.
|
|
|
|
This script provides a number of syndication feed and xml-based
|
|
metadata options to PmWiki, including Atom, RSS 2.0, RSS 1.0 (RDF),
|
|
and the Dublin Core Metadata extensions. This module is typically
|
|
activated from a local configuration file via a line such as
|
|
|
|
if ($action == 'atom') include_once("$FarmD/scripts/feeds.php");
|
|
if ($action == 'dc') include_once("$FarmD/scripts/feeds.php");
|
|
|
|
When enabled, ?action=atom, ?action=rss, and ?action=rdf produce
|
|
syndication feeds based on any wikitrail contained in the page,
|
|
or, for Category pages, on the pages in the category. The feeds
|
|
are generated using pagelist, thus one can include parameters such
|
|
as count=, list=, order=, etc. in the url to adjust the feed output.
|
|
|
|
?action=dc will normally generate Dublin Core Metadata for the
|
|
current page only, but placing a group=, trail=, or link= argument
|
|
in the url causes it to generate metadata for all pages in the
|
|
associated group, trail, or backlink.
|
|
|
|
There are a large number of customizations available, most of which
|
|
are controlled by the $FeedFmt array. Elements $FeedFmt look like
|
|
|
|
$FeedFmt['atom']['feed']['rights'] = 'All Rights Reserved';
|
|
|
|
where the first index corresponds to the action (?action=atom),
|
|
the second index indicates a per-feed or per-item element, and
|
|
the third index is the name of the element being generated.
|
|
The above setting would therefore generate a
|
|
"<rights>All Rights Reserved</rights>" in the feed for
|
|
?action=atom. If the value of an entry begins with a '<',
|
|
then feeds.php doesn't automatically add the tag around it.
|
|
Elements can also be callable functions which are called to
|
|
generate the appropriate output.
|
|
|
|
For example, to set the RSS 2.0 <author> element to the
|
|
value of the last author to modify a page, one can set
|
|
(in local/config.php):
|
|
|
|
$FeedFmt['rss']['item']['author'] = '$LastModifiedBy';
|
|
|
|
To use the RSS 2.0 <description> element to contain the
|
|
change summary of the most recent edit, set
|
|
|
|
$FeedFmt['rss']['item']['description'] = '$LastModifiedSummary';
|
|
|
|
Feeds.php can also be combined with attachments to support
|
|
podcasting via ?action=rss. Any page such as "PageName"
|
|
that has an mp3 attachment with the same name as the page
|
|
("PageName.mp3") will have an appropriate <enclosure> element
|
|
in the feed output. The set of allowed attachments can be
|
|
extended using the $RSSEnclosureFmt array:
|
|
|
|
$RSSEnclosureFmt = array('{$Name}.mp3', '{$Name}.mp4');
|
|
|
|
References:
|
|
http://www.atomenabled.org/developers/syndication/
|
|
http://dublincore.org/documents/dcmes-xml/
|
|
http://en.wikipedia.org/wiki/Podcasting
|
|
*/
|
|
|
|
## Settings for ?action=atom
|
|
SDVA($FeedFmt['atom']['feed'], array(
|
|
'_header' => 'Content-type: text/xml; charset="$Charset"',
|
|
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
|
|
<feed xmlns="http://www.w3.org/2005/Atom">'."\n",
|
|
'_end' => "</feed>\n",
|
|
'title' => '$WikiTitle',
|
|
'link' => '<link rel="self" href="{$PageUrl}?action=atom" />',
|
|
'id' => '{$PageUrl}?action=atom',
|
|
'updated' => '$FeedISOTime',
|
|
'author' => "<author><name>$WikiTitle</name></author>\n",
|
|
'generator' => '$Version',
|
|
'logo' => '$PageLogoUrl'));
|
|
SDVA($FeedFmt['atom']['item'], array(
|
|
'_start' => "<entry>\n",
|
|
'id' => '{$PageUrl}',
|
|
'title' => '{$Title}',
|
|
'updated' => '$ItemISOTime',
|
|
'link' => "<link rel=\"alternate\" href=\"{\$PageUrl}\" />\n",
|
|
'author' => "<author><name>{\$LastModifiedBy}</name></author>\n",
|
|
'summary' => '{$Description}',
|
|
'category' => "<category term=\"\$Category\" />\n",
|
|
'_end' => "</entry>\n"));
|
|
|
|
## Settings for ?action=dc
|
|
SDVA($FeedFmt['dc']['feed'], array(
|
|
'_header' => 'Content-type: text/xml; charset="$Charset"',
|
|
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
|
|
<!DOCTYPE rdf:RDF PUBLIC "-//DUBLIN CORE//DCMES DTD 2002/07/31//EN"
|
|
"http://dublincore.org/documents/2002/07/31/dcmes-xml/dcmes-xml-dtd.dtd">
|
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
xmlns:dc="http://purl.org/dc/elements/1.1/">'."\n",
|
|
'_end' => "</rdf:RDF>\n"));
|
|
SDVA($FeedFmt['dc']['item'], array(
|
|
'_start' => "<rdf:Description rdf:about=\"{\$PageUrl}\">\n",
|
|
'dc:title' => '{$Title}',
|
|
'dc:identifier' => '{$PageUrl}',
|
|
'dc:date' => '$ItemISOTime',
|
|
'dc:type' => 'Text',
|
|
'dc:format' => 'text/html',
|
|
'dc:description' => '{$Description}',
|
|
'dc:subject' => "<dc:subject>\$Category</dc:subject>\n",
|
|
'dc:publisher' => '$WikiTitle',
|
|
'dc:author' => '{$LastModifiedBy}',
|
|
'_end' => "</rdf:Description>\n"));
|
|
|
|
## RSS 2.0 settings for ?action=rss
|
|
SDVA($FeedFmt['rss']['feed'], array(
|
|
'_header' => 'Content-type: text/xml; charset="$Charset"',
|
|
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
|
|
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
<channel>'."\n",
|
|
'_end' => "</channel>\n</rss>\n",
|
|
'title' => '$WikiTitle | {$Group} / {$Title}',
|
|
'link' => '{$PageUrl}?action=rss',
|
|
'description' => '{$Group}.{$Title}',
|
|
'lastBuildDate' => '$FeedRSSTime'));
|
|
SDVA($FeedFmt['rss']['item'], array(
|
|
'_start' => "<item>\n",
|
|
'_end' => "</item>\n",
|
|
'title' => '{$Group} / {$Title}',
|
|
'link' => '{$PageUrl}',
|
|
'description' => '{$Description}',
|
|
'dc:contributor' => '{$LastModifiedBy}',
|
|
'dc:date' => '$ItemISOTime',
|
|
'pubDate' => '$ItemRSSTime',
|
|
'enclosure' => 'RSSEnclosure'));
|
|
|
|
## RDF 1.0, for ?action=rdf
|
|
SDVA($FeedFmt['rdf']['feed'], array(
|
|
'_header' => 'Content-type: text/xml; charset="$Charset"',
|
|
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
|
|
<rdf:RDF xmlns="http://purl.org/rss/1.0/"
|
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
<channel rdf:about="{$PageUrl}?action=rdf">'."\n",
|
|
'title' => '$WikiTitle | {$Group} / {$Title}',
|
|
'link' => '{$PageUrl}?action=rdf',
|
|
'description' => '{$Group}.{$Title}',
|
|
'dc:date' => '$FeedISOTime',
|
|
'items' => "<items>\n<rdf:Seq>\n\$FeedRDFSeq</rdf:Seq>\n</items>\n",
|
|
'_items' => "</channel>\n",
|
|
'_end' => "</rdf:RDF>\n"));
|
|
SDVA($FeedFmt['rdf']['item'], array(
|
|
'_start' => "<item rdf:about=\"{\$PageUrl}\">\n",
|
|
'_end' => "</item>\n",
|
|
'title' => '$WikiTitle | {$Group} / {$Title}',
|
|
'link' => '{$PageUrl}',
|
|
'description' => '{$Description}',
|
|
'dc:date' => '$ItemISOTime'));
|
|
|
|
foreach(array_keys($FeedFmt) as $k) {
|
|
SDV($HandleActions[$k], 'HandleFeed');
|
|
SDV($HandleAuth[$k], 'read');
|
|
}
|
|
|
|
function HandleFeed($pagename, $auth = 'read') {
|
|
global $FeedFmt, $action, $PCache, $FmtV, $TimeISOZFmt, $RSSTimeFmt,
|
|
$FeedPageListOpt, $FeedCategoryOpt, $FeedTrailOpt,
|
|
$FeedDescPatterns, $CategoryGroup, $EntitiesTable;
|
|
SDV($RSSTimeFmt, 'D, d M Y H:i:s \G\M\T');
|
|
SDV($FeedDescPatterns,
|
|
array('/<[^>]*$/' => ' ', '/\\w+$/' => '', '/<[^>]+>/' => ''));
|
|
$FeedPageListOpt = (array)@$FeedPageListOpt;
|
|
SDVA($FeedCategoryOpt, array('link' => $pagename));
|
|
SDVA($FeedTrailOpt, array('trail' => $pagename, 'count' => 10));
|
|
|
|
$f = $FeedFmt[$action];
|
|
$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
|
|
if (!$page) Abort("?cannot generate feed");
|
|
$feedtime = $page['time'];
|
|
|
|
# determine list of pages to display
|
|
if (@($_REQUEST['trail'] || $_REQUEST['group'] || $_REQUEST['link']
|
|
|| $_REQUEST['name']))
|
|
$opt = $FeedPageListOpt;
|
|
else if (preg_match("/^$CategoryGroup\\./", $pagename))
|
|
$opt = $FeedCategoryOpt;
|
|
else if ($action != 'dc') $opt = $FeedTrailOpt;
|
|
else {
|
|
PCache($pagename, $page);
|
|
$pagelist = array($pagename);
|
|
}
|
|
if (!@$pagelist) {
|
|
$opt = array_merge($opt, @$_REQUEST);
|
|
$pagelist = MakePageList($pagename, $opt, 0);
|
|
}
|
|
|
|
# process list of pages in feed
|
|
$rdfseq = '';
|
|
$pl = array();
|
|
foreach($pagelist as $pn) {
|
|
if (!PageExists($pn)) continue;
|
|
if (!isset($PCache[$pn]['time']))
|
|
{ $page = ReadPage($pn, READPAGE_CURRENT); PCache($pn, $page); }
|
|
$pc = & $PCache[$pn];
|
|
$pl[] = $pn;
|
|
$rdfseq .= FmtPageName("<rdf:li resource=\"{\$PageUrl}\" />\n", $pn);
|
|
if ($pc['time'] > $feedtime) $feedtime = $pc['time'];
|
|
if (@$opt['count'] && count($pl) >= $opt['count']) break;
|
|
}
|
|
$pagelist = $pl;
|
|
|
|
$FmtV['$FeedRDFSeq'] = $rdfseq;
|
|
$FmtV['$FeedISOTime'] = gmstrftime($TimeISOZFmt, $feedtime);
|
|
$FmtV['$FeedRSSTime'] = gmdate($RSSTimeFmt, $feedtime);
|
|
# format start of feed
|
|
$out = FmtPageName($f['feed']['_start'], $pagename);
|
|
|
|
# format feed elements
|
|
foreach($f['feed'] as $k => $v) {
|
|
if ($k{0} == '_' || !$v) continue;
|
|
$x = FmtPageName($v, $pagename);
|
|
if (!$x) continue;
|
|
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
|
|
}
|
|
|
|
# format items in feed
|
|
if (@$f['feed']['_items'])
|
|
$out .= FmtPageName($f['feed']['_items'], $pagename);
|
|
foreach($pagelist as $pn) {
|
|
$page = &$PCache[$pn];
|
|
$FmtV['$ItemDesc'] = @$page['description'];
|
|
$FmtV['$ItemISOTime'] = gmstrftime($TimeISOZFmt, $page['time']);
|
|
$FmtV['$ItemRSSTime'] = gmdate($RSSTimeFmt, $page['time']);
|
|
|
|
$out .= FmtPageName($f['item']['_start'], $pn);
|
|
foreach((array)@$f['item'] as $k => $v) {
|
|
if ($k{0} == '_' || !$v) continue;
|
|
if (is_callable($v)) { $out .= $v($pn, $page, $k); continue; }
|
|
if (strpos($v, '$LastModifiedBy') !== false && !@$page['author'])
|
|
continue;
|
|
if (strpos($v, '$Category') !== false) {
|
|
if (preg_match_all("/(?<=^|,)$CategoryGroup\\.([^,]+)/",
|
|
@$page['targets'], $match)) {
|
|
foreach($match[1] as $c) {
|
|
$FmtV['$Category'] = $c;
|
|
$out .= FmtPageName($v, $pn);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
$x = FmtPageName($v, $pn);
|
|
if (!$x) continue;
|
|
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
|
|
}
|
|
$out .= FmtPageName($f['item']['_end'], $pn);
|
|
}
|
|
$out .= FmtPageName($f['feed']['_end'], $pagename);
|
|
foreach((array)@$f['feed']['_header'] as $fmt)
|
|
header(FmtPageName($fmt, $pagename));
|
|
print str_replace(array_keys($EntitiesTable),
|
|
array_values($EntitiesTable), $out);
|
|
}
|
|
|
|
## RSSEnclosure is called in ?action=rss to generate <enclosure>
|
|
## tags for any pages that have an attached "PageName.mp3" file.
|
|
## The set of attachments to enclose is given by $RSSEnclosureFmt.
|
|
function RSSEnclosure($pagename, &$page, $k) {
|
|
global $RSSEnclosureFmt, $UploadFileFmt, $UploadExts;
|
|
if (!function_exists('MakeUploadName')) return '';
|
|
SDV($RSSEnclosureFmt, array('{$Name}.mp3'));
|
|
$encl = '';
|
|
foreach((array)$RSSEnclosureFmt as $fmt) {
|
|
$path = FmtPageName($fmt, $pagename);
|
|
$upname = MakeUploadName($pagename, $path);
|
|
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
|
|
if (file_exists($filepath)) {
|
|
$length = filesize($filepath);
|
|
$type = @$UploadExts[preg_replace('/.*\\./', '', $filepath)];
|
|
$url = LinkUpload($pagename, 'Attach:', $path, '', '', '$LinkUrl');
|
|
$encl .= "<$k url='$url' length='$length' type='$type' />";
|
|
}
|
|
}
|
|
return $encl;
|
|
}
|
|
|
|
## Since most feeds don't understand html character entities, we
|
|
## convert the common ones to their numeric form here.
|
|
SDVA($EntitiesTable, array(
|
|
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"
|
|
' ' => ' ',
|
|
'¡' => '¡',
|
|
'¢' => '¢',
|
|
'£' => '£',
|
|
'¤' => '¤',
|
|
'¥' => '¥',
|
|
'¦' => '¦',
|
|
'§' => '§',
|
|
'¨' => '¨',
|
|
'©' => '©',
|
|
'ª' => 'ª',
|
|
'«' => '«',
|
|
'¬' => '¬',
|
|
'­' => '­',
|
|
'®' => '®',
|
|
'¯' => '¯',
|
|
'°' => '°',
|
|
'±' => '±',
|
|
'²' => '²',
|
|
'³' => '³',
|
|
'´' => '´',
|
|
'µ' => 'µ',
|
|
'¶' => '¶',
|
|
'·' => '·',
|
|
'¸' => '¸',
|
|
'¹' => '¹',
|
|
'º' => 'º',
|
|
'»' => '»',
|
|
'¼' => '¼',
|
|
'½' => '½',
|
|
'¾' => '¾',
|
|
'¿' => '¿',
|
|
'À' => 'À',
|
|
'Á' => 'Á',
|
|
'Â' => 'Â',
|
|
'Ã' => 'Ã',
|
|
'Ä' => 'Ä',
|
|
'Å' => 'Å',
|
|
'Æ' => 'Æ',
|
|
'Ç' => 'Ç',
|
|
'È' => 'È',
|
|
'É' => 'É',
|
|
'Ê' => 'Ê',
|
|
'Ë' => 'Ë',
|
|
'Ì' => 'Ì',
|
|
'Í' => 'Í',
|
|
'Î' => 'Î',
|
|
'Ï' => 'Ï',
|
|
'Ð' => 'Ð',
|
|
'Ñ' => 'Ñ',
|
|
'Ò' => 'Ò',
|
|
'Ó' => 'Ó',
|
|
'Ô' => 'Ô',
|
|
'Õ' => 'Õ',
|
|
'Ö' => 'Ö',
|
|
'×' => '×',
|
|
'Ø' => 'Ø',
|
|
'Ù' => 'Ù',
|
|
'Ú' => 'Ú',
|
|
'Û' => 'Û',
|
|
'Ü' => 'Ü',
|
|
'Ý' => 'Ý',
|
|
'Þ' => 'Þ',
|
|
'ß' => 'ß',
|
|
'à' => 'à',
|
|
'á' => 'á',
|
|
'â' => 'â',
|
|
'ã' => 'ã',
|
|
'ä' => 'ä',
|
|
'å' => 'å',
|
|
'æ' => 'æ',
|
|
'ç' => 'ç',
|
|
'è' => 'è',
|
|
'é' => 'é',
|
|
'ê' => 'ê',
|
|
'ë' => 'ë',
|
|
'ì' => 'ì',
|
|
'í' => 'í',
|
|
'î' => 'î',
|
|
'ï' => 'ï',
|
|
'ð' => 'ð',
|
|
'ñ' => 'ñ',
|
|
'ò' => 'ò',
|
|
'ó' => 'ó',
|
|
'ô' => 'ô',
|
|
'õ' => 'õ',
|
|
'ö' => 'ö',
|
|
'÷' => '÷',
|
|
'ø' => 'ø',
|
|
'ù' => 'ù',
|
|
'ú' => 'ú',
|
|
'û' => 'û',
|
|
'ü' => 'ü',
|
|
'ý' => 'ý',
|
|
'þ' => 'þ',
|
|
'ÿ' => 'ÿ',
|
|
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent"
|
|
'"' => '"',
|
|
#'&' => '&#38;',
|
|
#'<' => '&#60;',
|
|
#'>' => '>',
|
|
''' => ''',
|
|
'Œ' => 'Œ',
|
|
'œ' => 'œ',
|
|
'Š' => 'Š',
|
|
'š' => 'š',
|
|
'Ÿ' => 'Ÿ',
|
|
'ˆ' => 'ˆ',
|
|
'˜' => '˜',
|
|
' ' => ' ',
|
|
' ' => ' ',
|
|
' ' => ' ',
|
|
'‌' => '‌',
|
|
'‍' => '‍',
|
|
'‎' => '‎',
|
|
'‏' => '‏',
|
|
'–' => '–',
|
|
'—' => '—',
|
|
'‘' => '‘',
|
|
'’' => '’',
|
|
'‚' => '‚',
|
|
'“' => '“',
|
|
'”' => '”',
|
|
'„' => '„',
|
|
'†' => '†',
|
|
'‡' => '‡',
|
|
'‰' => '‰',
|
|
'‹' => '‹',
|
|
'›' => '›',
|
|
'€' => '€',
|
|
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent"
|
|
'ƒ' => 'ƒ',
|
|
'Α' => 'Α',
|
|
'Β' => 'Β',
|
|
'Γ' => 'Γ',
|
|
'Δ' => 'Δ',
|
|
'Ε' => 'Ε',
|
|
'Ζ' => 'Ζ',
|
|
'Η' => 'Η',
|
|
'Θ' => 'Θ',
|
|
'Ι' => 'Ι',
|
|
'Κ' => 'Κ',
|
|
'Λ' => 'Λ',
|
|
'Μ' => 'Μ',
|
|
'Ν' => 'Ν',
|
|
'Ξ' => 'Ξ',
|
|
'Ο' => 'Ο',
|
|
'Π' => 'Π',
|
|
'Ρ' => 'Ρ',
|
|
'Σ' => 'Σ',
|
|
'Τ' => 'Τ',
|
|
'Υ' => 'Υ',
|
|
'Φ' => 'Φ',
|
|
'Χ' => 'Χ',
|
|
'Ψ' => 'Ψ',
|
|
'Ω' => 'Ω',
|
|
'α' => 'α',
|
|
'β' => 'β',
|
|
'γ' => 'γ',
|
|
'δ' => 'δ',
|
|
'ε' => 'ε',
|
|
'ζ' => 'ζ',
|
|
'η' => 'η',
|
|
'θ' => 'θ',
|
|
'ι' => 'ι',
|
|
'κ' => 'κ',
|
|
'λ' => 'λ',
|
|
'μ' => 'μ',
|
|
'ν' => 'ν',
|
|
'ξ' => 'ξ',
|
|
'ο' => 'ο',
|
|
'π' => 'π',
|
|
'ρ' => 'ρ',
|
|
'ς' => 'ς',
|
|
'σ' => 'σ',
|
|
'τ' => 'τ',
|
|
'υ' => 'υ',
|
|
'φ' => 'φ',
|
|
'χ' => 'χ',
|
|
'ψ' => 'ψ',
|
|
'ω' => 'ω',
|
|
'ϑ' => 'ϑ',
|
|
'ϒ' => 'ϒ',
|
|
'ϖ' => 'ϖ',
|
|
'•' => '•',
|
|
'…' => '…',
|
|
'′' => '′',
|
|
'″' => '″',
|
|
'‾' => '‾',
|
|
'⁄' => '⁄',
|
|
'℘' => '℘',
|
|
'ℑ' => 'ℑ',
|
|
'ℜ' => 'ℜ',
|
|
'™' => '™',
|
|
'ℵ' => 'ℵ',
|
|
'←' => '←',
|
|
'↑' => '↑',
|
|
'→' => '→',
|
|
'↓' => '↓',
|
|
'↔' => '↔',
|
|
'↵' => '↵',
|
|
'⇐' => '⇐',
|
|
'⇑' => '⇑',
|
|
'⇒' => '⇒',
|
|
'⇓' => '⇓',
|
|
'⇔' => '⇔',
|
|
'∀' => '∀',
|
|
'∂' => '∂',
|
|
'∃' => '∃',
|
|
'∅' => '∅',
|
|
'∇' => '∇',
|
|
'∈' => '∈',
|
|
'∉' => '∉',
|
|
'∋' => '∋',
|
|
'∏' => '∏',
|
|
'∑' => '∑',
|
|
'−' => '−',
|
|
'∗' => '∗',
|
|
'√' => '√',
|
|
'∝' => '∝',
|
|
'∞' => '∞',
|
|
'∠' => '∠',
|
|
'∧' => '∧',
|
|
'∨' => '∨',
|
|
'∩' => '∩',
|
|
'∪' => '∪',
|
|
'∫' => '∫',
|
|
'∴' => '∴',
|
|
'∼' => '∼',
|
|
'≅' => '≅',
|
|
'≈' => '≈',
|
|
'≠' => '≠',
|
|
'≡' => '≡',
|
|
'≤' => '≤',
|
|
'≥' => '≥',
|
|
'⊂' => '⊂',
|
|
'⊃' => '⊃',
|
|
'⊄' => '⊄',
|
|
'⊆' => '⊆',
|
|
'⊇' => '⊇',
|
|
'⊕' => '⊕',
|
|
'⊗' => '⊗',
|
|
'⊥' => '⊥',
|
|
'⋅' => '⋅',
|
|
'⌈' => '⌈',
|
|
'⌉' => '⌉',
|
|
'⌊' => '⌊',
|
|
'⌋' => '⌋',
|
|
'⟨' => '〈',
|
|
'⟩' => '〉',
|
|
'◊' => '◊',
|
|
'♠' => '♠',
|
|
'♣' => '♣',
|
|
'♥' => '♥',
|
|
'♦' => '♦'));
|
|
|