def getPage(requestPath, lang): response = None title = 'Web Fundamentals' leftNav = '- No Left Nav Found - ' toc = '- No TOC Found - ' template = 'gae/article.tpl' fileLocations = [ os.path.join(SOURCE_PATH, lang, requestPath) + '.md', os.path.join(SOURCE_PATH, 'en', requestPath) + '.md', os.path.join(SOURCE_PATH, lang, requestPath) + '.jshtml', os.path.join(SOURCE_PATH, 'en', requestPath) + '.jshtml', ] for fileLocation in fileLocations: if os.path.isfile(fileLocation): content = open(fileLocation, 'r').read() content = content.decode('utf8') # If it's a .jshtml file, just serve it. if fileLocation.endswith('.jshtml'): return content dateUpdated = re.search(r"{# wf_updated_on:[ ]?(.*)[ ]?#}", content) if dateUpdated is None: logging.warn('Missing wf_updated_on tag.') dateUpdated = 'Unknown' else: dateUpdated = dateUpdated.group(1) ## Injects markdown includes into the markdown as appropriate includes = re.findall(r'^<<.+?\.md>>(?m)', content) for includeTag in includes: fileName = includeTag.replace('<<', '').replace('>>', '') fileName = os.path.join(os.path.dirname(fileLocation), fileName) include = devsiteHelper.readFile(fileName, lang) if include is None: include = 'Warning: Unable to find included markdown file.\n\n' content = content.replace(includeTag, include) # Remove any comments {# something #} from the markdown content = re.sub(r'{#.+?#}', '', content) content = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', content) # Show warning for unsupported elements for tag in UNSUPPORTED_TAGS: if re.search(tag, content) is not None: logging.error(' - Unsupported tag: ' + tag) replaceWith = '<aside class="warning">Web<strong>Fundamentals</strong>: ' replaceWith += '<span>Unsupported tag: <code>' + tag + '</code></span></aside>' content = re.sub(tag, replaceWith, content) # Show warning for template tags if re.search('{{', content) is not None: logging.warn(' - Warning: possible unescaped template tag') # Render any DevSite specific tags content = devsiteHelper.renderDevSiteContent(content, lang) # If it's a markdown file, parse it to HTML if fileLocation.endswith('.md'): content = re.sub( r'^Note: (.*?)\n^\n(?ms)', r'<aside class="note" markdown="1"><strong>Note:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Caution: (.*?)\n^\n(?ms)', r'<aside class="caution" markdown="1"><strong>Caution:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Warning: (.*?)\n^\n(?ms)', r'<aside class="warning" markdown="1"><strong>Warning:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Key Point: (.*?)\n^\n(?ms)', r'<aside class="key-point" markdown="1"><strong>Key Point:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Key Term: (.*?)\n^\n(?ms)', r'<aside class="key-term" markdown="1"><strong>Key Term:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Objective: (.*?)\n^\n(?ms)', r'<aside class="objective" markdown="1"><strong>Objective:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Success: (.*?)\n^\n(?ms)', r'<aside class="success" markdown="1"><strong>Success:</strong> <span>\1</span></aside>', content) content = re.sub( r'^Dogfood: (.*?)\n^\n(?ms)', r'<aside class="dogfood" markdown="1"><strong>Dogfood:</strong> <span>\1</span></aside>', content) # Adds a set of markdown extensions available to us on DevSite ext = [ 'markdown.extensions.attr_list', # Adds support for {: #someid } 'markdown.extensions.meta', # Removes the meta data from the top of the doc 'markdown.extensions.toc', # Generate the TOC for the right side 'markdown.extensions.tables', # Support for Markdown Tables 'markdown.extensions.def_list', # Support for definition lists 'markdown.extensions.extra' # Enabled markdown extras ] md = markdown.Markdown(extensions=ext) content = md.convert(content) # Reads the book.yaml file and generate the lefthand nav if 'book_path' in md.Meta and len(md.Meta['book_path']) == 1: bookPath = md.Meta['book_path'][0] leftNav = devsiteHelper.getLeftNav(requestPath, bookPath, lang) # Checks if the page should be displayed in full width mode if 'full_width' in md.Meta and len(md.Meta['full_width']) == 1: fullWidth = md.Meta['full_width'][0] if fullWidth.lower().strip() == 'true': template = 'gae/home.tpl' # Build the table of contents & transform so it fits within DevSite toc = md.toc toc = toc.strip() # Strips the outer wrapper and the page title from the doc toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc) toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc) # Add appropriate classes toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc) toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc) toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc) # Replaces <pre> tags with prettyprint enabled tags content = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint">', content) # Get the page title from the markup. titleRO = re.search(r'<h1 class="page-title".*?>(.*?)<\/h1>', content) if titleRO: title = titleRO.group(1) gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/' gitHubEditUrl += 'master/src/content/' gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '') gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/' gitHubIssueUrl += 'new?title=Feedback for: ' + title + ' [' gitHubIssueUrl += lang + ']&body=' gitHubIssueUrl += gitHubEditUrl x = devsiteHelper.getFooterPromo() # Renders the content into the template response = render( template, { 'title': title, 'announcementBanner': devsiteHelper.getAnnouncementBanner(lang), 'gitHubIssueUrl': gitHubIssueUrl, 'gitHubEditUrl': gitHubEditUrl, 'requestPath': requestPath.replace('/index', ''), 'leftNav': leftNav, 'content': content, 'toc': toc, 'dateUpdated': dateUpdated, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() }) break return response
def parse(requestPath, fileLocation, rawYaml, lang='en'): body = '' parsedYaml = yaml.load(rawYaml) bookPath = parsedYaml['book_path'] bookYaml = devsiteHelper.parseBookYaml(bookPath, lang) projectPath = parsedYaml['project_path'] page = parsedYaml['landing_page'] rows = page['rows'] title = 'Web' banner = devsiteHelper.getAnnouncementBanner(projectPath, lang) header = 'Generic Page Header Here' customCss = '' lowerTabs = devsiteHelper.getLowerTabs(bookYaml) if 'custom_css_path' in page: customCss = '<link rel="stylesheet" href="' customCss += page['custom_css_path'] customCss += '">' if 'header' in page: header = '<div class="devsite-collapsible-section">' header += '<div class="devsite-header-background devsite-full-site-width">' header += '<div class="devsite-product-id-row devsite-full-site-width">' if 'description' in page['header']: header += '<div class="devsite-product-description-row">' header += '<div class="devsite-product-description">' header += page['header']['description'] header += '</div></div>' if 'buttons' in page['header']: header += '<div class="devsite-product-button-row">' for button in page['header']['buttons']: header += '<a class="button" href="' header += button['path'] + '">' + button['label'] + '</a>' header += '</div>' header += '</div></div></div>' if 'name' in page['header']: title = page['header']['name'] for row in rows: sectionClass = ['devsite-landing-row'] section = '<section class="[[SECTION_CLASSES]]">' if 'classname' in row: sectionClass.append(row['classname']) numItems = None if 'columns' in row: numItems = len(row['columns']) elif 'items' in row: numItems = len(row['items']) if numItems: sectionClass.append('devsite-landing-row-' + str(numItems) + '-up') if 'heading' in row: section += '<h2 id="' + devsiteHelper.slugify( row['heading']) + '">' section += row['heading'] + '</h2>' if 'items' in row: section += '<div class="devsite-landing-row-group">' section += parseIndexYamlItems(row['items']) section += '</div>' if 'columns' in row: for column in row['columns']: section += '<div class="devsite-landing-row-column">' if 'items' in column: section += parseIndexYamlItems(column['items']) section += '</div>' section += '</section>' section = section.replace('[[SECTION_CLASSES]]', ' '.join(sectionClass)) body += section body = devsiteHelper.renderDevSiteContent(body, lang) return render( 'gae/home.tpl', { 'title': title, 'announcementBanner': banner, 'requestPath': requestPath, 'lowerTabs': lowerTabs, 'customcss': customCss, 'header': header, 'content': body, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() })
def getPage(requestPath, lang): response = None title = 'Web Fundamentals' leftNav = '- No Left Nav Found - ' toc = '- No TOC Found - ' template = 'gae/article.tpl' fileLocations = [ os.path.join(SOURCE_PATH, lang, requestPath) + '.md', os.path.join(SOURCE_PATH, 'en', requestPath) + '.md', os.path.join(SOURCE_PATH, lang, requestPath) + '.jshtml', os.path.join(SOURCE_PATH, 'en', requestPath) + '.jshtml', ] for fileLocation in fileLocations: if os.path.isfile(fileLocation): content = open(fileLocation, 'r').read() content = content.decode('utf8') # If it's a .jshtml file, just serve it. if fileLocation.endswith('.jshtml'): return content dateUpdated = re.search(r"{# wf_updated_on:[ ]?(.*)[ ]?#}", content) if dateUpdated is None: logging.warn('Missing wf_updated_on tag.') dateUpdated = 'Unknown' else: dateUpdated = dateUpdated.group(1) ## Injects markdown includes into the markdown as appropriate includes = re.findall(r'^<<.+?\.md>>(?m)', content) for includeTag in includes: fileName = includeTag.replace('<<', '').replace('>>', '') fileName = os.path.join(os.path.dirname(fileLocation), fileName) include = devsiteHelper.readFile(fileName, lang) if include is None: include = 'Warning: Unable to find included markdown file.\n\n' content = content.replace(includeTag, include) # Remove any comments {# something #} from the markdown content = re.sub(r'{#.+?#}', '', content) content = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', content) # Show warning for unsupported elements for tag in UNSUPPORTED_TAGS: if re.search(tag, content) is not None: logging.error(' - Unsupported tag: ' + tag) replaceWith = '<aside class="warning">Web<strong>Fundamentals</strong>: ' replaceWith += '<span>Unsupported tag: <code>' + tag + '</code></span></aside>' content = re.sub(tag, replaceWith, content) # Show warning for template tags if re.search('{{', content) is not None: logging.warn(' - Warning: possible unescaped template tag') # Render any DevSite specific tags content = devsiteHelper.renderDevSiteContent(content, lang) # If it's a markdown file, parse it to HTML if fileLocation.endswith('.md'): content = re.sub(r'^Note: (.*?)\n^\n(?ms)', r'<aside class="note" markdown="1"><strong>Note:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Caution: (.*?)\n^\n(?ms)', r'<aside class="caution" markdown="1"><strong>Caution:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Warning: (.*?)\n^\n(?ms)', r'<aside class="warning" markdown="1"><strong>Warning:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Key Point: (.*?)\n^\n(?ms)', r'<aside class="key-point" markdown="1"><strong>Key Point:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Key Term: (.*?)\n^\n(?ms)', r'<aside class="key-term" markdown="1"><strong>Key Term:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Objective: (.*?)\n^\n(?ms)', r'<aside class="objective" markdown="1"><strong>Objective:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Success: (.*?)\n^\n(?ms)', r'<aside class="success" markdown="1"><strong>Success:</strong> <span>\1</span></aside>', content) content = re.sub(r'^Dogfood: (.*?)\n^\n(?ms)', r'<aside class="dogfood" markdown="1"><strong>Dogfood:</strong> <span>\1</span></aside>', content) # Adds a set of markdown extensions available to us on DevSite ext = [ 'markdown.extensions.attr_list', # Adds support for {: #someid } 'markdown.extensions.meta', # Removes the meta data from the top of the doc 'markdown.extensions.toc', # Generate the TOC for the right side 'markdown.extensions.tables', # Support for Markdown Tables 'markdown.extensions.extra', # Support for markdown='1' in tags 'markdown.extensions.def_list' # Support for definition lists ] md = markdown.Markdown(extensions=ext) content = md.convert(content) # Reads the book.yaml file and generate the lefthand nav if 'book_path' in md.Meta and len(md.Meta['book_path']) == 1: bookPath = md.Meta['book_path'][0] leftNav = devsiteHelper.getLeftNav(requestPath, bookPath, lang) # Checks if the page should be displayed in full width mode if 'full_width' in md.Meta and len(md.Meta['full_width']) == 1: fullWidth = md.Meta['full_width'][0] if fullWidth.lower().strip() == 'true': template = 'gae/home.tpl' # Build the table of contents & transform so it fits within DevSite toc = md.toc toc = toc.strip() # Strips the outer wrapper and the page title from the doc toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc) toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc) # Add appropriate classes toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc) toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc) toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc) # Replaces <pre> tags with prettyprint enabled tags content = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint">', content) # Get the page title from the markup. titleRO = re.search(r'<h1 class="page-title".*?>(.*?)<\/h1>', content) if titleRO: title = titleRO.group(1) gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/' gitHubEditUrl += 'master/src/content/' gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '') gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/' gitHubIssueUrl += 'new?title=Feedback for: ' + title + ' [' gitHubIssueUrl += lang + ']&body=' gitHubIssueUrl += gitHubEditUrl x = devsiteHelper.getFooterPromo() # Renders the content into the template response = render(template, { 'title': title, 'announcementBanner': devsiteHelper.getAnnouncementBanner(lang), 'gitHubIssueUrl': gitHubIssueUrl, 'gitHubEditUrl': gitHubEditUrl, 'requestPath': requestPath.replace('/index', ''), 'leftNav': leftNav, 'content': content, 'toc': toc, 'dateUpdated': dateUpdated, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() } ) break return response
def generateYaml(lang, requestPath, rawYaml): content = '' parsedYaml = yaml.load(rawYaml) page = parsedYaml['landing_page'] rows = page['rows'] title = 'Web' banner = devsiteHelper.getAnnouncementBanner(lang) header = 'Generic Page Header Here' customCss = '' if 'custom_css_path' in page: customCss = '<link rel="stylesheet" href="' customCss += page['custom_css_path'] customCss += '">' if 'header' in page: header = '<div class="devsite-collapsible-section">' header += '<div class="devsite-header-background devsite-full-site-width">' header += '<div class="devsite-product-id-row devsite-full-site-width">' if 'description' in page['header']: header += '<div class="devsite-product-description-row">' header += '<div class="devsite-product-description">' header += page['header']['description'] header += '</div></div>' if 'buttons' in page['header']: header += '<div class="devsite-product-button-row">' for button in page['header']['buttons']: header += '<a class="button" href="' header += button['path'] + '">' + button['label'] + '</a>' header += '</div>' header += '</div></div></div>' if 'name' in page['header']: title = page['header']['name'] for row in rows: sectionClass = ['devsite-landing-row'] section = '<section class="[[SECTION_CLASSES]]">' if 'classname' in row: sectionClass.append(row['classname']) numItems = None if 'columns' in row: numItems = len(row['columns']) elif 'items' in row: numItems = len(row['items']) if numItems: sectionClass.append('devsite-landing-row-' + str(numItems) + '-up') if 'heading' in row: section += '<h2 id="' + devsiteHelper.slugify(row['heading']) +'">' section += row['heading'] + '</h2>' if 'items' in row: section += parseIndexYamlItems(row['items']) if 'columns' in row: for column in row['columns']: section += '<div class="devsite-landing-row-column">' if 'items' in column: section += parseIndexYamlItems(column['items']) section += '</div>' section += '</section>' section = section.replace('[[SECTION_CLASSES]]', ' '.join(sectionClass)) content += section content = devsiteHelper.renderDevSiteContent(content, lang) text = render('gae/home.tpl', { 'title': title, 'announcementBanner': banner, 'requestPath': requestPath, 'customcss': customCss, 'header': header, 'content': content, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() } ) return text
def parse(requestPath, fileLocation, content, lang='en'): template = 'gae/article.tpl' ## Get the HTML tag htmlTag = re.search(r'<html.*?>', content) if htmlTag is None: log.warning('Does not contain <html> root element') else: htmlTag = htmlTag.group(0) # Check the HTML tag contains the devsite if htmlTag.find('devsite') == -1: return content # Isolate the <head> headStart = content.find('<head') headEnd = content.find('</head>') head = content[headStart:headEnd].strip() # Isolate the <body> bodyStart = content.find('<body') bodyEnd = content.rfind('</body>') body = content[bodyStart:bodyEnd].strip() body = re.sub(r'<body.*?>', '', body) dateUpdated = re.search(r"{# wf_updated_on:[ ]?(.*)[ ]?#}", content) if dateUpdated is None: dateUpdated = 'Unknown' else: dateUpdated = dateUpdated.group(1) # Remove any comments {# something #} body = re.sub(r'{#.+?#}', '', body) body = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', body) # Show warning for unsupported elements for tag in UNSUPPORTED_TAGS: if re.search(tag, body) is not None: logging.error(' - Unsupported tag: ' + tag) replaceWith = '<aside class="warning">Web<strong>Fundamentals</strong>: ' replaceWith += '<span>Unsupported tag: <code>' + tag + '</code></span></aside>' body = re.sub(tag, replaceWith, body) # Show warning for template tags if re.search('{{', body) is not None: logging.warn(' - Warning: possible unescaped template tag') # Render any DevSite specific tags body = devsiteHelper.renderDevSiteContent(body, lang) # Read the page title title = re.search('<title>(.*?)</title>', head) if title is None: title = '** UNKNOWN TITLE **' else: title = title.group(1) if body.find('<h1>') == -1: body = '<h1 class="page-title">' + title + '</h1>\n\n' + body # Read the book.yaml file and generate the left hand nav bookPath = re.search('name=\"book_path\" value=\"(.*?)\"', head) if bookPath is None: logging.error('Unable to read book_path') leftNav = 'Book not found.' lowerTabs = '' else: bookPath = bookPath.group(1) bookYaml = devsiteHelper.parseBookYaml(bookPath, lang) leftNav = devsiteHelper.getLeftNav(requestPath, bookYaml) lowerTabs = devsiteHelper.getLowerTabs(bookYaml) # Read the project.yaml file projectPath = re.search('name=\"project_path\" value=\"(.*?)\"', head) if bookPath is None: logging.error('Unable to read project_path') else: projectPath = projectPath.group(1) announcementBanner = devsiteHelper.getAnnouncementBanner( projectPath, lang) # Replaces <pre> tags with prettyprint enabled tags body = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint">', body) # Checks if the page should be displayed in full width mode fullWidth = re.search('name=\"full_width\" value=\"true\"', head) if fullWidth is not None: template = 'gae/home.tpl' # # Build the table of contents & transform so it fits within DevSite toc = '- TOC NYI - ' # toc = md.toc # toc = toc.strip() # # Strips the outer wrapper and the page title from the doc # toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc) # toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc) # # Add appropriate classes # toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc) # toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc) # toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc) gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/' gitHubEditUrl += 'master/src/content/' gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '') gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/' gitHubIssueUrl += 'new?title=Feedback for: ' + title + ' [' gitHubIssueUrl += lang + ']&body=' gitHubIssueUrl += gitHubEditUrl # Renders the content into the template return render( template, { 'title': title, 'head': head, 'announcementBanner': announcementBanner, 'lowerTabs': lowerTabs, 'gitHubIssueUrl': gitHubIssueUrl, 'gitHubEditUrl': gitHubEditUrl, 'requestPath': requestPath.replace('/index', ''), 'leftNav': leftNav, 'content': body, 'toc': toc, 'dateUpdated': dateUpdated, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() })
def parse(requestPath, fileLocation, rawYaml, lang='en'): body = '' parsedYaml = yaml.load(rawYaml) bookPath = parsedYaml['book_path'] bookYaml = devsiteHelper.parseBookYaml(bookPath, lang) projectPath = parsedYaml['project_path'] page = parsedYaml['landing_page'] rows = page['rows'] title = 'Web' if 'title' in parsedYaml: title = parsedYaml['title'] headerTitle = None description = 'Description pulled from <code>_project.yaml</code>' headerButtons = None banner = devsiteHelper.getAnnouncementBanner(projectPath, lang) customHeader = None customCSS = None lowerTabs = devsiteHelper.getLowerTabs(bookYaml) if len(lowerTabs) <= 1: lowerTabs = None if 'custom_css_path' in page: customCSS = '<link rel="stylesheet" href="' customCSS += page['custom_css_path'] customCSS += '">' if 'header' in page: if 'custom_html' in page['header']: customHeader = page['header']['custom_html'] else: if 'name' in page['header']: headerTitle = page['header']['name'] if 'description' in page['header']: description = page['header']['description'] if 'buttons' in page['header']: headerButtons = [] for button in page['header']['buttons']: headerButton = '<a class="button" href="' headerButton += button['path'] + '">' + button[ 'label'] + '</a>' headerButtons.append(headerButton) for row in rows: sectionClass = ['devsite-landing-row'] section = '<section class="[[SECTION_CLASSES]]">' if 'classname' in row: sectionClass.append(row['classname']) numItems = None if 'columns' in row: numItems = len(row['columns']) elif 'items' in row: numItems = len(row['items']) if numItems: sectionClass.append('devsite-landing-row-' + str(numItems) + '-up') if 'heading' in row: section += '<h2 id="' + devsiteHelper.slugify( row['heading']) + '">' section += row['heading'] + '</h2>' if 'description' in row: section += '<p class="devsite-landing-row-description">' section += row['description'] + '</p>' if 'items' in row: section += '<div class="devsite-landing-row-group">' section += parseIndexYamlItems(row['items']) section += '</div>' if 'columns' in row: section += '<div class="devsite-landing-row-group">' for column in row['columns']: section += '<div class="devsite-landing-row-column">' # if 'items' in column: section += parseIndexYamlItems([column]) section += '</div>' section += '</div>' section += '</section>' section = section.replace('[[SECTION_CLASSES]]', ' '.join(sectionClass)) body += section body = devsiteHelper.renderDevSiteContent(body, lang) return render( 'gae/home.tpl', { 'title': title, 'headerTitle': title, 'description': description, 'headerButtons': headerButtons, 'announcementBanner': banner, 'requestPath': requestPath, 'lowerTabs': lowerTabs, 'customCSS': customCSS, 'customHeader': customHeader, 'content': body, 'lang': lang, 'footerPromo': devsiteHelper.getFooterPromo(), 'footerLinks': devsiteHelper.getFooterLinkBox() })