summaryrefslogtreecommitdiff
path: root/sandbox/ianb
diff options
context:
space:
mode:
authorwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
committerwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
commitd77fdfef70e08114f57cbef5d91707df8717ea9f (patch)
tree49444e3486c0c333cb7b33dfa721296c08ee4ece /sandbox/ianb
parent53cd16ca6ca5f638cbe5956988e88f9339e355cf (diff)
parent3993c4097756e9885bcfbd07cb1cc1e4e95e50e4 (diff)
downloaddocutils-0.4.tar.gz
Release 0.4: tagging released revisiondocutils-0.4
git-svn-id: http://svn.code.sf.net/p/docutils/code/tags/docutils-0.4@4268 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'sandbox/ianb')
-rw-r--r--sandbox/ianb/extractor/default.css245
-rw-r--r--sandbox/ianb/extractor/extractor.py336
-rw-r--r--sandbox/ianb/wiki/Wiki.py250
-rw-r--r--sandbox/ianb/wiki/docs/Wiki.txt54
4 files changed, 0 insertions, 885 deletions
diff --git a/sandbox/ianb/extractor/default.css b/sandbox/ianb/extractor/default.css
deleted file mode 100644
index 05e43aab5..000000000
--- a/sandbox/ianb/extractor/default.css
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
-:Author: David Goodger
-:Contact: goodger@users.sourceforge.net
-:date: $Date$
-:version: $Revision$
-:copyright: This stylesheet has been placed in the public domain.
-
-Default cascading style sheet for the HTML output of Docutils.
-*/
-
-.topic {
- margin-left: 5em;
-}
-
-.topic-title {
- margin-left: -1em;
-}
-
-body {
- background-color: #eeeeee;
- font-family: Arial, sans-serif;
-}
-
-em {
- font-family: Times New Roman, Times, serif;
-}
-
-li {
- list-style-type: circle;
-}
-
-a.target {
- color: blue }
-
-a.toc-backref {
- text-decoration: none ;
- color: black }
-
-a:hover {
- background-color: #cccccc;
-}
-
-cite {
- font-style: normal;
- font-family: monospace;
- font-weight: bold;
-}
-
-dd {
- margin-bottom: 0.5em }
-
-div.abstract {
- margin: 2em 5em }
-
-div.abstract p.topic-title {
- font-weight: bold ;
- text-align: center }
-
-div.attention, div.caution, div.danger, div.error, div.hint,
-div.important, div.note, div.tip, div.warning {
- // margin: 2em ;
- background-color: #cccccc;
- align: center;
- //width: 60%;
- // border: medium outset ;
- padding: 3px;
- }
-
-div.attention p.admonition-title, div.caution p.admonition-title,
-div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title {
- color: red ;
- font-weight: bold ;
- font-family: sans-serif;
- text-align: center }
-
-div.hint p.admonition-title, div.important p.admonition-title,
-div.note p.admonition-title, div.tip p.admonition-title {
- font-weight: bold ;
- font-family: sans-serif;
- text-align: center }
-
-div.dedication {
- margin: 2em 5em ;
- text-align: center ;
- font-style: italic }
-
-div.dedication p.topic-title {
- font-weight: bold ;
- font-style: normal }
-
-div.figure {
- margin-left: 2em }
-
-div.footer, div.header {
- font-size: smaller }
-
-div.system-messages {
- margin: 5em }
-
-div.system-messages h1 {
- color: red }
-
-div.system-message {
- border: medium outset ;
- padding: 1em }
-
-div.system-message p.system-message-title {
- color: red ;
- font-weight: bold }
-
-div.topic {
- margin: 2em }
-
-h1, h2, h3, h4, h5, h6 {
- font-family: Helvetica, Arial, sans-serif;
- border: thin solid black;
- background-color: #cccccc;
- -moz-border-radius: 8px;
- padding: 4px;
- }
-
-h1.title {
- text-align: center;
- background-color: #444499;
- color: #eeeeee;
- border: medium solid black;
- -moz-border-radius: 20px;
- }
-
-h2.subtitle {
- text-align: center }
-
-hr {
- width: 75% }
-
-ol.simple, ul.simple {
- margin-bottom: 1em }
-
-ol.arabic {
- list-style: decimal }
-
-ol.loweralpha {
- list-style: lower-alpha }
-
-ol.upperalpha {
- list-style: upper-alpha }
-
-ol.lowerroman {
- list-style: lower-roman }
-
-ol.upperroman {
- list-style: upper-roman }
-
-p.caption {
- font-style: italic }
-
-p.credits {
- font-style: italic ;
- font-size: smaller }
-
-p.first {
- margin-top: 0 }
-
-p.label {
- white-space: nowrap }
-
-p.topic-title {
- font-weight: bold }
-
-pre.address {
- margin-bottom: 0 ;
- margin-top: 0 ;
- font-family: serif ;
- font-size: 100% }
-
-pre.line-block {
- font-family: serif ;
- font-size: 100% }
-
-pre.literal-block, pre.doctest-block {
- margin-left: 2em ;
- margin-right: 2em ;
- background-color: #ffffff;
- border: thin black solid;
- padding: 5px;
-}
-
-span.classifier {
- font-family: sans-serif ;
- font-style: oblique }
-
-span.classifier-delimiter {
- font-family: sans-serif ;
- font-weight: bold }
-
-span.interpreted {
- font-family: sans-serif }
-
-span.option-argument {
- font-style: italic }
-
-span.pre {
- white-space: pre }
-
-span.problematic {
- color: red }
-
-table {
- margin-top: 0.5em ;
- margin-bottom: 0.5em }
-
-table.citation {
- border-left: solid thin gray ;
- padding-left: 0.5ex }
-
-table.docinfo {
- margin: 2em 4em }
-
-table.footnote {
- border-left: solid thin black ;
- padding-left: 0.5ex }
-
-td, th {
- padding-left: 0.5em ;
- padding-right: 0.5em ;
- vertical-align: top }
-
-td > p:first-child, th > p:first-child {
- margin-top: 0em }
-
-th.docinfo-name, th.field-name {
- font-weight: bold ;
- text-align: left ;
- white-space: nowrap }
-
-h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
- font-size: 100% }
-
-tt {
- //background-color: #eeeeee;
- color: #000066 }
-
-ul.auto-toc {
- list-style-type: none }
diff --git a/sandbox/ianb/extractor/extractor.py b/sandbox/ianb/extractor/extractor.py
deleted file mode 100644
index 9411ecf6a..000000000
--- a/sandbox/ianb/extractor/extractor.py
+++ /dev/null
@@ -1,336 +0,0 @@
-#!/usr/bin/env python
-"""
-This module extracts the documentation from a module, and converts
-it into a single reST document.
-
-Usage:
- ./extractor.py some_module.py > some_module.txt
-For more:
- ./extractor.py --help
-
-The document is based on the module's docstring -- no other
-documentation is implicitly included.
-
-Other documentation can be explicitly included by using the directives
-``.. inline:: function_or_class`` or ``.. inline-all::``.
-
-The first directive includes the docstring from that function or
-class. When the directive is encountered inside a class, it can refer
-either to the global or local namespace, as in ``..inline::
-Document.add_child`` or ``.. inline:: add_child``.
-
-The second directive will include all children of the module or class,
-except those which start with a ``"_"`` (i.e., private), those that
-have ``:ignore:`` anywhere in their docstring, or those that have
-already been included.
-
-You can also force a docstring to be ignored by using
-``.. ignore:: function_or_class``. This is useful for properties,
-whose documentation will not be extracted, or other times when
-you want to document the function or class separately from its
-docstring.
-
-TODO
-----
-
-* Allow docstrings to override the normal function argument
- list (e.g., to hide non-public optional arguments).
-* Some sort of table of contents support.
-
-"""
-
-
-import os, re, sys
-from docutils.readers.python import moduleparser
-
-class Document:
-
- def __init__(self, node, module):
- self.node = node
- self.parts = []
- self.children = {}
- self.module = module
-
- def add_child(self, child):
- self.children[child.name] = child
- self.parts.append(child)
-
- def process(self):
- for child in self.node.children:
- self.process_node(child)
-
- def process_node(self, node):
- if isinstance(node, moduleparser.Docstring):
- self.parts.append(node.text)
- elif isinstance(node, moduleparser.Class):
- self.add_child(Class(node, self.module))
- elif isinstance(node, moduleparser.Function):
- self.add_child(Function(node, self.module))
-
- def documentation(self, context=None):
- if context is None:
- return Document.documentation(self, DocContext())
- newParts = []
- for part in self.parts:
- if type(part) is type(""):
- doc = self.module.substitute(part, self, context)
- newParts.append(doc + "\n")
- continue
- if part.name.startswith('_') \
- and not part.name.startswith('__'):
- continue
- if context.seen(part):
- continue
- doc = part.documentation(context)
- if doc.lower().find(':ignore:') != -1:
- continue
- newParts.append(indent(doc))
- context.setSeen(self)
- return '\n'.join(newParts)
-
-class DocContext:
-
- def __init__(self):
- self.partsSeen = {}
-
- def seen(self, obj):
- return self.partsSeen.has_key(obj)
-
- def setSeen(self, obj):
- self.partsSeen[obj] = 1
-
-class Module(Document):
-
- def __init__(self, filename, text=None):
- self.filename = filename
- if text is None:
- text = open(filename).read()
- self.module_text = text
- self.name = os.path.splitext(os.path.basename(filename))[0]
- node = moduleparser.parse_module(text, filename)
- Document.__init__(self, node, self)
- self.imports = []
- self.subber = InlineSubstitution(self)
- self.process()
-
- def substitute(self, s, currentNode=None, context=None):
- return self.subber.substitute(s, currentNode, context)
-
- def process_node(self, node):
- if isinstance(node, moduleparser.Import):
- self.imports.append((node.names, node.from_name))
- else:
- Document.process_node(self, node)
-
- def documentation(self, context=None):
- return "%s\n%s\n\n%s" % \
- (self.name,
- "=" * len(self.name),
- Document.documentation(self, context=None))
-
- def importText(self, im):
- if im[1]:
- return 'from %s import %s' % (im[1], im[0])
- else:
- return 'import %s' % im[0]
-
-class InlineSubstitution:
-
- def __init__(self, rootNode):
- self.rootNode = rootNode
-
- _inlineRE = re.compile(r'( *).. +inline:: *(.*)')
- _inlineAllRE = re.compile(r'( *).. +inline-all:: *')
- _ignoreRE = re.compile(r'( *).. ignore:: *(.*)\n?')
-
- def substitute(self, s, currentNode=None, context=None):
- if currentNode is None:
- currentNode = self.rootNode
- s = self._ignoreRE.sub(
- lambda m, cur=currentNode, con=context, : self._ignoreSubber(m, cur, con),
- s)
- s = self._inlineRE.sub(
- lambda m, cur=currentNode, con=context: self._inlineSubber(m, cur, con),
- s)
- s = self._inlineAllRE.sub(
- lambda m, cur=currentNode, con=context: self._inlineAllSubber(m, cur, con),
- s)
- return s
-
- def _inlineSubber(self, match, currentNode, context):
- level = len(match.group(1))
- name = match.group(2).strip().split('.')
- child = self._getChild(name, currentNode)
- return indent(self.substitute(child.documentation(context), child), level)
-
- def _ignoreSubber(self, match, currentNode, context):
- name = match.group(2).strip().split('.')
- child = self._getChild(name, currentNode)
- context.setSeen(child)
- return ''
-
- def _getChild(self, name, currentNode):
- nameList = name
- obj = currentNode
- while 1:
- if not nameList:
- return obj
- if not obj.children.has_key(nameList[0]):
- if currentNode is self.rootNode:
- raise NameError, '%s not found' % '.'.join(name)
- else:
- return self._getChild(name, self.rootNode)
- obj = obj.children[nameList[0]]
- nameList = nameList[1:]
-
- def _inlineAllSubber(self, match, currentNode, context):
- level = len(match.group(1))
- children = currentNode.children.keys()
- children.sort()
- children = [currentNode.children[name] for name in children]
- allDocs = []
- for child in children:
- if child.name.startswith('_'):
- continue
- doc = child.documentation(context)
- if doc.lower().find(':ignore:') != -1:
- continue
- allDocs.append(self.substitute(doc, child))
- return indent('\n'.join(allDocs), level)
-
-
-
-class Function(Document):
-
- def __init__(self, node, module):
- Document.__init__(self, node, module)
- self.name = node.name
- self.parameters = []
- self.process()
-
- def process_node(self, node):
- if isinstance(node, moduleparser.ParameterList):
- for parameter in node.children:
- self.process_parameter(parameter)
- else:
- Document.process_node(self, node)
-
- def process_parameter(self, param):
- ## @@: handle defaults, *args, etc.
- if param.name == 'self':
- return
- if param.children:
- val = ('default', (param.name, param.children[0].text))
- elif isinstance(param, moduleparser.ExcessPositionalArguments):
- val = ('*', param.name)
- elif isinstance(param, moduleparser.ExcessKeywordArguments):
- val = ('**', param.name)
- else:
- val = ('normal', param.name)
- self.parameters.append(val)
-
- def documentation(self, context):
- d = "`%s(%s)`:\n" % (self.name,
- ', '.join([self.parameterText(p)
- for p in self.parameters]))
- doc = Document.documentation(self, context)
- if not doc:
- doc = "Not documented."
- return d + indent(doc) + "\n"
-
- def parameterText(self, param):
- t, name = param
- if t == 'normal':
- return name
- elif t == 'default':
- return '%s=%s' % (name[0], name[1])
- elif t == '*':
- return '*%s' % name
- elif t == '**':
- return '**%s' % name
- else:
- assert 0
-
-class Class(Document):
-
- def __init__(self, node, module):
- Document.__init__(self, node, module)
- self.bases = []
- self.name = node.name
- for attr, value in node.attlist():
- if attr == 'bases':
- self.bases = value
- self.process()
-
- def documentation(self, context):
- if self.bases:
- base = 'class `%s(%s)`:' % (self.name, self.bases)
- else:
- base = 'class `%s`:' % self.name
- return base + "\n" + indent(Document.documentation(self, context))
-
-
-def indent(text, amount=4):
- return '\n'.join([(' '*amount) + line for line in text.split('\n')])
-
-def create_documentation(filename, output):
- if type(output) is type(""):
- output = open(output, 'w')
- mod = Module(filename)
- doc = mod.documentation()
- if doc.lower().find(':ignore:') == -1:
- output.write(mod.documentation())
-
-########################################
-## Command-line interface
-########################################
-
-def main(options, args):
- for arg in args:
- if os.path.isdir(arg) and options.recurse:
- main(options, [os.path.join(arg, f) for f in os.listdir(arg)])
- continue
- if options.recurse and not arg.endswith('.py'):
- continue
- filename = os.path.splitext(arg)[0] + ".txt"
- filename = os.path.join(options.output, filename)
- filename = os.path.normpath(filename)
- if not options.quiet:
- sys.stdout.write('%s -> %s ...' % (os.path.normpath(arg),
- filename))
- sys.stdout.flush()
- create_documentation(arg, filename)
- if not options.quiet:
- sys.stdout.write('done.\n')
- sys.stdout.flush()
-
-if __name__ == '__main__':
- from optparse import OptionParser
- parser = OptionParser()
- parser.add_option('-r', '--recurse',
- action="store_true",
- dest="recurse",
- default=0,
- help="recurse into subdirectories")
- parser.add_option('-o', '--output',
- dest="output",
- help="write documentation to FILE (or directory)",
- metavar="FILE")
- parser.add_option('-q', '--quiet',
- dest="quiet",
- default=0,
- action="store_true",
- help="be quiet")
- (options, args) = parser.parse_args()
- if len(args) == 1 and options.output \
- and not os.path.isdir(options.output):
- if options.output == '-':
- options.output = sys.stdout
- create_documentation(args[0], options.output)
- else:
- if not options.output:
- options.output = '.'
- main(options, args)
-
-
-
diff --git a/sandbox/ianb/wiki/Wiki.py b/sandbox/ianb/wiki/Wiki.py
deleted file mode 100644
index b7cfb3eef..000000000
--- a/sandbox/ianb/wiki/Wiki.py
+++ /dev/null
@@ -1,250 +0,0 @@
-"""
-The Wiki module primarily exports the `WikiPage` class:
-"""
-
-import os, re, time
-from docutils import core, io
-from docutils import readers
-
-__all__ = ['WikiPage', 'allPages', 'recentPages',
- 'searchTitles', 'search', 'css']
-
-## All the Wiki pages will be kept in this directory:
-pageDir = '/usr/home/ianb/w/pypaper/pages/'
-
-class WikiPage(object):
- """
- WikiPage is a class to represent one page in a WikiWikiWeb [#]_.
- The page may or may not yet exist -- that is, it may not yet
- have content.
-
- .. [#] http://c2.com/cgi-bin/wiki
-
- It has the following properties and methods:
-
- `html`:
- A read-only property giving the HTML for the page.
- If the page does not yet have content the text
- ``"This page has not yet been created"`` is returned.
- `text`:
- The text for the page. To save new text, simply
- assign to this property.
- `title`:
- The title of the page.
- `name`:
- The name of the page -- a canonical identifier.
- Related to the title, but not necessarily the
- same.
- .. ignore: html
- .. ignore: text
- .. ignore: setText
- .. ignore: title
-
- """
-
- def __init__(self, pageName):
- """
- Each page has a name, which is a unique identifier, for example
- ``"FrontPage"``, which identifies the page in the URL and
- for linking.
- """
- self.name = pageName
-
- def basePath(self):
- """
- :Ignore: yes
- Returns the base path (sans extension) for this page
- """
- return _basePath(self.name)
-
- basePath = property(basePath)
-
- def exists(self):
- """Does this page have content yet?"""
- return _exists(self.name)
-
- def html(self):
- """Returns text of HTML for page (HTML fragment only)"""
- if self.exists():
- html = open(self.basePath + ".html").read()
- html = self._subWikiLinks(html)
- return html
- else:
- return 'This page has not yet been created.'
-
- html = property(html)
-
- def preview(self, text):
- """Returns an HTML preview of the text"""
- return self._subWikiLinks(self._convertText(text))
-
- _wikiLinkRE = re.compile(r'(<a [^>]* href=")!(.*?)("[^>]*>)(.*?)(</a>)',
- re.I+re.S)
-
- def _subWikiLinks(self, text):
- return self._wikiLinkRE.sub(self._subLink, ' %s ' % text)
-
- def _subLink(self, match):
- if _exists(match.group(2)):
- return match.group(1) + match.group(2) + match.group(3) + match.group(4) + match.group(5)
- else:
- return '<span class="nowiki">%s%s%s%s?%s</span>' \
- % (match.group(4), match.group(1), match.group(2),
- match.group(3), match.group(5))
-
- def text(self):
- """
- The text of the page. ReStructuredText is used, though the
- parsing is internal to the module. You can assign to this
- property to save new text for the page.
- """
- if self.exists():
- return open(self.basePath + ".txt").read()
- else:
- return ''
-
- def setText(self, text):
- """Sets the text for the page (and updates cached HTML at the
- same time)"""
- f = open(self.basePath + ".txt", 'w')
- f.write(text)
- f.close()
- f = open(self.basePath + ".html", 'w')
- f.write(self._convertText(text))
- f.close()
-
- def _convertText(self, text):
- return self._cleanHTML(core.publish_string(
- source=text,
- reader=Reader(),
- parser_name='restructuredtext',
- writer_name='html'))
-
- def _cleanHTML(self, html):
- return html[html.find('<body>'):html.find('</body>')]
-
- text = property(text, setText)
-
- def searchMatches(self, text):
- """
- :Ignore: yes
- """
- return self.searchTitleMatches(text) \
- or self.text().lower().find(text.lower()) != -1
-
- def searchTitleMatches(self, text):
- """
- :Ignore: yes
- """
- return self.title().lower().find(text.lower()) != -1
-
- def modifiedDate(self):
- """Date modified (integer timestamp)"""
- return os.stat(self.basePath + ".txt").st_mtime
-
- modifiedDate = property(modifiedDate)
-
- def modifiedDateText(self):
- """Text representation of modified date"""
- return time.strftime("%a %m/%d/%y", time.gmtime(self.modifiedDate()))
-
- modifiedDateText = property(modifiedDateText)
-
- def title(self):
- """Page title"""
- return self.name
-
- title = property(title)
-
-"""
-Methods for searching the wiki pages:
-"""
-
-def allPages():
- """All pages with content in the system"""
- return [WikiPage(page[:-4])
- for page in os.listdir(pageDir)
- if page.endswith('.txt')]
-
-def recentPages():
- """All pages, sorted by date modified, most recent first"""
- pages = allPages()
- pages.sort(lambda a, b: cmp(b.modifiedDate(), a.modifiedDate()))
- return pages
-
-def searchTitles(text):
- """Search page titles for ``text``, returning list of pages"""
- return [page for page in allPages()
- if page.searchTitleMatches(text)]
-
-def search(text):
- """Search titles and bodies of pages for ``text``, returning list
- of pages"""
- return [page for page in allPages()
- if page.searchMatches(text)]
-
-
-def _basePath(name):
- return os.path.join(pageDir, name)
-
-def _exists(name):
- return os.path.exists(_basePath(name) + ".html")
-
-"""
-There is one module global to be printed at the top of
-every Wiki page:
-
- `css`:
- The HTML to put the proper CSS at the top of the page. This
- should be put in the ``<head>`` section of the page.
-"""
-
-try:
- f = open('default.css')
-except IOError:
- css = ""
-else:
- css = '<style type="text/css">\n%s</style>\n' % f.read()
- f.close()
-
-########################################
-## reST-specific stuff
-########################################
-
-
-from docutils import nodes
-from docutils.readers import standalone
-from docutils.transforms import Transform
-
-class WikiLinkResolver(nodes.SparseNodeVisitor):
- ":Ignore: yes"
-
- def visit_reference(self, node):
- if node.resolved or not node.hasattr('refname'):
- return
- refname = node['refname']
- node.resolved = 1
- node['class'] = 'wiki'
- # I put a ! here to distinguish Wiki links from other
- # links -- Wiki links have to be fixed up at view time,
- # to distinguish between dangling and resolved Wiki
- # links.
- node['refuri'] = '!' + refname
- del node['refname']
-
-class WikiLink(Transform):
- ":Ignore: yes"
-
- default_priority = 800
-
- def apply(self):
- visitor = WikiLinkResolver(self.document)
- self.document.walk(visitor)
-
-class Reader(standalone.Reader):
- ":Ignore: yes"
-
- supported = standalone.Reader.supported + ('wiki',)
-
- def get_transforms(self):
- return standalone.Reader.get_transforms(self) + [WikiLink]
diff --git a/sandbox/ianb/wiki/docs/Wiki.txt b/sandbox/ianb/wiki/docs/Wiki.txt
deleted file mode 100644
index c63094529..000000000
--- a/sandbox/ianb/wiki/docs/Wiki.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-Wiki
-====
-
-The Wiki module primarily exports the `WikiPage` class:
-
- class `WikiPage(object)`:
- WikiPage is a class to represent one page in a WikiWikiWeb [#]_.
- The page may or may not yet exist -- that is, it may not yet
- have content.
-
- .. [#] http://c2.com/cgi-bin/wiki
-
- It has the following properties and methods:
-
- `html`:
- A read-only property giving the HTML for the page.
- If the page does not yet have content the text
- ``"This page has not yet been created"`` is returned.
- `text`:
- The text for the page. To save new text, simply
- assign to this property.
- `title`:
- The title of the page.
- `name`:
- The name of the page -- a canonical identifier.
- Related to the title, but not necessarily the
- same.
- `exists()`:
- Does this page have content yet?
- `modifiedDate()`:
- Date modified (integer timestamp)
- `modifiedDateText()`:
- Text representation of modified date
- `preview(text)`:
- Returns an HTML preview of the text
-
-There are also several searching methods:
-
- `allPages()`:
- All pages with content in the system
- `recentPages()`:
- All pages, sorted by date modified, most recent first
- `search(text)`:
- Search titles and bodies of pages for ``text``, returning list
- of pages
- `searchTitles(text)`:
- Search page titles for ``text``, returning list of pages
-
-There is one module global to be printed at the top of
-every Wiki page:
-
- `css`:
- The HTML to put the proper CSS at the top of the page. This
- should be put in the ``<head>`` section of the page. \ No newline at end of file