diff options
Diffstat (limited to 'nikola/plugins/compile_rest')
| -rw-r--r-- | nikola/plugins/compile_rest/__init__.py | 138 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/dummy.py | 44 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/gist_directive.py | 56 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/listing.py | 121 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/slides.py | 65 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/soundcloud.py | 50 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/vimeo.py | 118 | ||||
| -rw-r--r-- | nikola/plugins/compile_rest/youtube.py | 69 |
8 files changed, 0 insertions, 661 deletions
diff --git a/nikola/plugins/compile_rest/__init__.py b/nikola/plugins/compile_rest/__init__.py deleted file mode 100644 index 3d41571..0000000 --- a/nikola/plugins/compile_rest/__init__.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2012 Roberto Alsina y otros. - -# Permission is hereby granted, free of charge, to any -# person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the -# Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the -# Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice -# shall be included in all copies or substantial portions of -# the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -from __future__ import unicode_literals -import codecs -import os - -try: - import docutils.core - import docutils.io - from docutils.parsers.rst import directives - - from .listing import Listing, CodeBlock - directives.register_directive('code-block', CodeBlock) - directives.register_directive('sourcecode', CodeBlock) - directives.register_directive('listing', Listing) - from .youtube import Youtube - directives.register_directive('youtube', Youtube) - from .vimeo import Vimeo - directives.register_directive('vimeo', Vimeo) - from .slides import Slides - directives.register_directive('slides', Slides) - from .gist_directive import GitHubGist - directives.register_directive('gist', GitHubGist) - from .soundcloud import SoundCloud - directives.register_directive('soundcloud', SoundCloud) - has_docutils = True -except ImportError: - has_docutils = False - -from nikola.plugin_categories import PageCompiler - - -class CompileRest(PageCompiler): - """Compile reSt into HTML.""" - - name = "rest" - - def compile_html(self, source, dest): - """Compile reSt into HTML.""" - if not has_docutils: - raise Exception('To build this site, you need to install the ' - '"docutils" package.') - try: - os.makedirs(os.path.dirname(dest)) - except: - pass - error_level = 100 - with codecs.open(dest, "w+", "utf8") as out_file: - with codecs.open(source, "r", "utf8") as in_file: - data = in_file.read() - output, error_level, deps = rst2html( - data, settings_overrides={ - 'initial_header_level': 2, - 'record_dependencies': True, - 'stylesheet_path': None, - 'link_stylesheet': True, - 'syntax_highlight': 'short', - }) - out_file.write(output) - deps_path = dest + '.dep' - if deps.list: - with codecs.open(deps_path, "wb+", "utf8") as deps_file: - deps_file.write('\n'.join(deps.list)) - else: - if os.path.isfile(deps_path): - os.unlink(deps_path) - if error_level < 3: - return True - else: - return False - - def create_post(self, path, onefile=False, **kw): - metadata = {} - metadata.update(self.default_metadata) - metadata.update(kw) - d_name = os.path.dirname(path) - if not os.path.isdir(d_name): - os.makedirs(os.path.dirname(path)) - with codecs.open(path, "wb+", "utf8") as fd: - if onefile: - for k, v in metadata.items(): - fd.write('.. {0}: {1}\n'.format(k, v)) - fd.write("\nWrite your post here.") - - -def rst2html(source, source_path=None, source_class=docutils.io.StringInput, - destination_path=None, reader=None, reader_name='standalone', - parser=None, parser_name='restructuredtext', writer=None, - writer_name='html', settings=None, settings_spec=None, - settings_overrides=None, config_section=None, - enable_exit_status=None): - """ - Set up & run a `Publisher`, and return a dictionary of document parts. - Dictionary keys are the names of parts, and values are Unicode strings; - encoding is up to the client. For programmatic use with string I/O. - - For encoded string input, be sure to set the 'input_encoding' setting to - the desired encoding. Set it to 'unicode' for unencoded Unicode string - input. Here's how:: - - publish_parts(..., settings_overrides={'input_encoding': 'unicode'}) - - Parameters: see `publish_programmatically`. - """ - output, pub = docutils.core.publish_programmatically( - source=source, source_path=source_path, source_class=source_class, - destination_class=docutils.io.StringOutput, - destination=None, destination_path=destination_path, - reader=reader, reader_name=reader_name, - parser=parser, parser_name=parser_name, - writer=writer, writer_name=writer_name, - settings=settings, settings_spec=settings_spec, - settings_overrides=settings_overrides, - config_section=config_section, - enable_exit_status=enable_exit_status) - return pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies diff --git a/nikola/plugins/compile_rest/dummy.py b/nikola/plugins/compile_rest/dummy.py deleted file mode 100644 index 39543fd..0000000 --- a/nikola/plugins/compile_rest/dummy.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2012 Roberto Alsina y otros. - -# Permission is hereby granted, free of charge, to any -# person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the -# Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the -# Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice -# shall be included in all copies or substantial portions of -# the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -"""A stupid codeblock replacement for neanderthals and users of Debian Sid.""" - -from __future__ import unicode_literals - -from docutils import nodes -from docutils.parsers.rst import Directive, directives - -CODE = '<pre>{0}</pre>' - - -class CodeBlock(Directive): - required_arguments = 1 - has_content = True - - def run(self): - """ Required by the Directive interface. Create docutils nodes """ - return [nodes.raw('', CODE.format('\n'.join(self.content)), format='html')] - -directives.register_directive('code', CodeBlock) diff --git a/nikola/plugins/compile_rest/gist_directive.py b/nikola/plugins/compile_rest/gist_directive.py deleted file mode 100644 index 1506519..0000000 --- a/nikola/plugins/compile_rest/gist_directive.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is public domain according to its author, Brian Hsu - -from docutils.parsers.rst import Directive, directives -from docutils import nodes - -try: - import requests -except ImportError: - requests = None # NOQA - - -class GitHubGist(Directive): - """ Embed GitHub Gist. - - Usage: - .. gist:: GIST_ID - - """ - - required_arguments = 1 - optional_arguments = 1 - option_spec = {'file': directives.unchanged} - final_argument_whitespace = True - has_content = False - - def get_raw_gist_with_filename(self, gistID, filename): - url = '/'.join(("https://raw.github.com/gist", gistID, filename)) - return requests.get(url).text - - def get_raw_gist(self, gistID): - url = "https://raw.github.com/gist/{0}".format(gistID) - return requests.get(url).text - - def run(self): - if requests is None: - print('To use the gist directive, you need to install the ' - '"requests" package.') - return [] - gistID = self.arguments[0].strip() - embedHTML = "" - rawGist = "" - - if 'file' in self.options: - filename = self.options['file'] - rawGist = (self.get_raw_gist_with_filename(gistID, filename)) - embedHTML = ('<script src="https://gist.github.com/{0}.js' - '?file={1}"></script>').format(gistID, filename) - else: - rawGist = (self.get_raw_gist(gistID)) - embedHTML = ('<script src="https://gist.github.com/{0}.js">' - '</script>').format(gistID) - - return [nodes.raw('', embedHTML, format='html'), - nodes.raw('', '<noscript>', format='html'), - nodes.literal_block('', rawGist), - nodes.raw('', '</noscript>', format='html')] diff --git a/nikola/plugins/compile_rest/listing.py b/nikola/plugins/compile_rest/listing.py deleted file mode 100644 index 1b816f5..0000000 --- a/nikola/plugins/compile_rest/listing.py +++ /dev/null @@ -1,121 +0,0 @@ -# -*- coding: utf-8 -*-
-# Copyright (c) 2012 Roberto Alsina y otros.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-""" Define and register a listing directive using the existing CodeBlock """
-
-
-from __future__ import unicode_literals
-from codecs import open as codecs_open # for patching purposes
-try:
- from urlparse import urlunsplit
-except ImportError:
- from urllib.parse import urlunsplit # NOQA
-
-from docutils import core
-from docutils.parsers.rst import directives
-try:
- from docutils.parsers.rst.directives.body import CodeBlock
-except ImportError: # docutils < 0.9 (Debian Sid For The Loss)
- from dummy import CodeBlock # NOQA
-
-import os
-
-
-class Listing(CodeBlock):
- """ listing directive: create a CodeBlock from file
-
- Usage:
-
- .. listing:: nikola.py python
- :number-lines:
-
- """
- has_content = False
- required_arguments = 1
- optional_arguments = 1
-
- option_spec = {
- 'start-at': directives.unchanged,
- 'end-at': directives.unchanged,
- 'start-after': directives.unchanged,
- 'end-before': directives.unchanged,
- }
-
- def run(self):
- fname = self.arguments.pop(0)
- with codecs_open(os.path.join('listings', fname), 'rb+', 'utf8') as fileobject:
- self.content = fileobject.read().splitlines()
- self.trim_content()
- target = urlunsplit(("link", 'listing', fname, '', ''))
- generated_nodes = (
- [core.publish_doctree('`{0} <{1}>`_'.format(fname, target))[0]])
- generated_nodes += self.get_code_from_file(fileobject)
- return generated_nodes
-
- def trim_content(self):
- """Cut the contents based in options."""
- start = 0
- end = len(self.content)
- if 'start-at' in self.options:
- for start, l in enumerate(self.content):
- if self.options['start-at'] in l:
- break
- else:
- start = 0
- elif 'start-before' in self.options:
- for start, l in enumerate(self.content):
- if self.options['start-before'] in l:
- if start > 0:
- start -= 1
- break
- else:
- start = 0
- if 'end-at' in self.options:
- for end, l in enumerate(self.content):
- if self.options['end-at'] in l:
- break
- else:
- end = len(self.content)
- elif 'end-before' in self.options:
- for end, l in enumerate(self.content):
- if self.options['end-before'] in l:
- end -= 1
- break
- else:
- end = len(self.content)
-
- self.content = self.content[start:end]
-
- def get_code_from_file(self, data):
- """ Create CodeBlock nodes from file object content """
- return super(Listing, self).run()
-
- def assert_has_content(self):
- """ Listing has no content, override check from superclass """
- pass
-
-
-directives.register_directive('listing', Listing)
diff --git a/nikola/plugins/compile_rest/slides.py b/nikola/plugins/compile_rest/slides.py deleted file mode 100644 index 57fb754..0000000 --- a/nikola/plugins/compile_rest/slides.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2012 Roberto Alsina y otros. - -# Permission is hereby granted, free of charge, to any -# person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the -# Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the -# Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice -# shall be included in all copies or substantial portions of -# the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -from __future__ import unicode_literals - -from docutils import nodes -from docutils.parsers.rst import Directive, directives - - -class Slides(Directive): - """ Restructured text extension for inserting slideshows.""" - has_content = True - - def run(self): - if len(self.content) == 0: - return - output = [] - output.append(""" - <div id="myCarousel" class="carousel slide"> - <ol class="carousel-indicators"> - """) - for i in range(len(self.content)): - if i == 0: - classname = 'class="active"' - else: - classname = '' - output.append(' <li data-target="#myCarousel" data-slide-to="{0}" {1}></li>'.format(i, classname)) - output.append("""</ol> - <div class="carousel-inner"> - """) - for i, image in enumerate(self.content): - if i == 0: - classname = "item active" - else: - classname = "item" - output.append("""<div class="{0}"><img src="{1}" alt="" style="margin: 0 auto 0 auto;"></div>""".format(classname, image)) - output.append("""</div> - <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a> - <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a> - </div>""") - return [nodes.raw('', '\n'.join(output), format='html')] - - -directives.register_directive('slides', Slides) diff --git a/nikola/plugins/compile_rest/soundcloud.py b/nikola/plugins/compile_rest/soundcloud.py deleted file mode 100644 index 6bdd4d5..0000000 --- a/nikola/plugins/compile_rest/soundcloud.py +++ /dev/null @@ -1,50 +0,0 @@ -# coding: utf8 - - -from docutils import nodes -from docutils.parsers.rst import Directive, directives - - -CODE = ("""<iframe width="{width}" height="{height}" -scrolling="no" frameborder="no" -src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/tracks/""" - """{sid}"> -</iframe>""") - - -class SoundCloud(Directive): - """ Restructured text extension for inserting SoundCloud embedded music - - Usage: - .. soundcloud:: <sound id> - :height: 400 - :width: 600 - - """ - has_content = True - required_arguments = 1 - option_spec = { - 'width': directives.positive_int, - 'height': directives.positive_int, - } - - def run(self): - """ Required by the Directive interface. Create docutils nodes """ - self.check_content() - options = { - 'sid': self.arguments[0], - 'width': 600, - 'height': 160, - } - options.update(self.options) - return [nodes.raw('', CODE.format(**options), format='html')] - - def check_content(self): - """ Emit a deprecation warning if there is content """ - if self.content: - raise self.warning("This directive does not accept content. The " - "'key=value' format for options is deprecated, " - "use ':key: value' instead") - - -directives.register_directive('soundcloud', SoundCloud) diff --git a/nikola/plugins/compile_rest/vimeo.py b/nikola/plugins/compile_rest/vimeo.py deleted file mode 100644 index c1dc143..0000000 --- a/nikola/plugins/compile_rest/vimeo.py +++ /dev/null @@ -1,118 +0,0 @@ -# coding: utf8 -# Copyright (c) 2012 Roberto Alsina y otros. - -# Permission is hereby granted, free of charge, to any -# person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the -# Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the -# Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice -# shall be included in all copies or substantial portions of -# the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -from docutils import nodes -from docutils.parsers.rst import Directive, directives - -try: - import requests -except ImportError: - requests = None # NOQA -try: - import json # python 2.6 or higher -except ImportError: - try: - import simplejson as json # NOQA - except ImportError: - json = None - - -CODE = """<iframe src="http://player.vimeo.com/video/{vimeo_id}" -width="{width}" height="{height}" -frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen> -</iframe> -""" - -VIDEO_DEFAULT_HEIGHT = 500 -VIDEO_DEFAULT_WIDTH = 281 - - -class Vimeo(Directive): - """ Restructured text extension for inserting vimeo embedded videos - - Usage: - .. vimeo:: 20241459 - :height: 400 - :width: 600 - - """ - has_content = True - required_arguments = 1 - option_spec = { - "width": directives.positive_int, - "height": directives.positive_int, - } - - # set to False for not querying the vimeo api for size - request_size = True - - def run(self): - self.check_content() - options = { - 'vimeo_id': self.arguments[0], - 'width': VIDEO_DEFAULT_WIDTH, - 'height': VIDEO_DEFAULT_HEIGHT, - } - if self.request_size: - self.check_modules() - self.set_video_size() - options.update(self.options) - return [nodes.raw('', CODE.format(**options), format='html')] - - def check_modules(self): - if requests is None: - raise Exception("To use the Vimeo directive you need to install " - "the requests module.") - if json is None: - raise Exception("To use the Vimeo directive you need python 2.6 " - "or to install the simplejson module.") - - def set_video_size(self): - # Only need to make a connection if width and height aren't provided - if 'height' not in self.options or 'width' not in self.options: - self.options['height'] = VIDEO_DEFAULT_HEIGHT - self.options['width'] = VIDEO_DEFAULT_WIDTH - - if json: # we can attempt to retrieve video attributes from vimeo - try: - url = ('http://vimeo.com/api/v2/video/{0}' - '.json'.format(self.arguments[0])) - data = requests.get(url).text - video_attributes = json.loads(data)[0] - self.options['height'] = video_attributes['height'] - self.options['width'] = video_attributes['width'] - except Exception: - # fall back to the defaults - pass - - def check_content(self): - if self.content: - raise self.warning("This directive does not accept content. The " - "'key=value' format for options is deprecated, " - "use ':key: value' instead") - - -directives.register_directive('vimeo', Vimeo) diff --git a/nikola/plugins/compile_rest/youtube.py b/nikola/plugins/compile_rest/youtube.py deleted file mode 100644 index 767be32..0000000 --- a/nikola/plugins/compile_rest/youtube.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) 2012 Roberto Alsina y otros. - -# Permission is hereby granted, free of charge, to any -# person obtaining a copy of this software and associated -# documentation files (the "Software"), to deal in the -# Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the -# Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice -# shall be included in all copies or substantial portions of -# the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -from docutils import nodes -from docutils.parsers.rst import Directive, directives - - -CODE = """\ -<iframe width="{width}" -height="{height}" -src="http://www.youtube.com/embed/{yid}?rel=0&hd=1&wmode=transparent" -></iframe>""" - - -class Youtube(Directive): - """ Restructured text extension for inserting youtube embedded videos - - Usage: - .. youtube:: lyViVmaBQDg - :height: 400 - :width: 600 - - """ - has_content = True - required_arguments = 1 - option_spec = { - "width": directives.positive_int, - "height": directives.positive_int, - } - - def run(self): - self.check_content() - options = { - 'yid': self.arguments[0], - 'width': 425, - 'height': 344, - } - options.update(self.options) - return [nodes.raw('', CODE.format(**options), format='html')] - - def check_content(self): - if self.content: - raise self.warning("This directive does not accept content. The " - "'key=value' format for options is deprecated, " - "use ':key: value' instead") - - -directives.register_directive('youtube', Youtube) |
