tags.
1194 | """
1195 | yield 0, ""
1196 | for tup in inner:
1197 | yield tup
1198 | yield 0, "
"
1199 |
1200 | def wrap(self, source, outfile):
1201 | """Return the source with a code, pre, and div."""
1202 | return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
1203 |
1204 | formatter = HtmlCodeFormatter(cssclass="codehilite", **formatter_opts)
1205 | return pygments.highlight(codeblock, lexer, formatter)
1206 |
1207 | def _code_block_sub(self, match):
1208 | codeblock = match.group(1)
1209 | codeblock = self._outdent(codeblock)
1210 | codeblock = self._detab(codeblock)
1211 | codeblock = codeblock.lstrip('\n') # trim leading newlines
1212 | codeblock = codeblock.rstrip() # trim trailing whitespace
1213 |
1214 | if "code-color" in self.extras and codeblock.startswith(":::"):
1215 | lexer_name, rest = codeblock.split('\n', 1)
1216 | lexer_name = lexer_name[3:].strip()
1217 | lexer = self._get_pygments_lexer(lexer_name)
1218 | codeblock = rest.lstrip("\n") # Remove lexer declaration line.
1219 | if lexer:
1220 | formatter_opts = self.extras['code-color'] or {}
1221 | colored = self._color_with_pygments(codeblock, lexer,
1222 | **formatter_opts)
1223 | return "\n\n%s\n\n" % colored
1224 |
1225 | codeblock = self._encode_code(codeblock)
1226 | return "\n\n%s\n
\n\n" % codeblock
1227 |
1228 | def _do_code_blocks(self, text):
1229 | """Process Markdown `` blocks."""
1230 | code_block_re = re.compile(r'''
1231 | (?:\n\n|\A)
1232 | ( # $1 = the code block -- one or more lines, starting with a space/tab
1233 | (?:
1234 | (?:[ ]{%d} | \t) # Lines must start with a tab or a tab-width of spaces
1235 | .*\n+
1236 | )+
1237 | )
1238 | ((?=^[ ]{0,%d}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
1239 | ''' % (self.tab_width, self.tab_width),
1240 | re.M | re.X)
1241 |
1242 | return code_block_re.sub(self._code_block_sub, text)
1243 |
1244 |
1245 | # Rules for a code span:
1246 | # - backslash escapes are not interpreted in a code span
1247 | # - to include one or or a run of more backticks the delimiters must
1248 | # be a longer run of backticks
1249 | # - cannot start or end a code span with a backtick; pad with a
1250 | # space and that space will be removed in the emitted HTML
1251 | # See `test/tm-cases/escapes.text` for a number of edge-case
1252 | # examples.
1253 | _code_span_re = re.compile(r'''
1254 | (?%s
" % c
1267 |
1268 | def _do_code_spans(self, text):
1269 | # * Backtick quotes are used for
spans.
1270 | #
1271 | # * You can use multiple backticks as the delimiters if you want to
1272 | # include literal backticks in the code span. So, this input:
1273 | #
1274 | # Just type ``foo `bar` baz`` at the prompt.
1275 | #
1276 | # Will translate to:
1277 | #
1278 | # Just type foo `bar` baz
at the prompt.
1279 | #
1280 | # There's no arbitrary limit to the number of backticks you
1281 | # can use as delimters. If you need three consecutive backticks
1282 | # in your code, use four for delimiters, etc.
1283 | #
1284 | # * You can use spaces to get literal backticks at the edges:
1285 | #
1286 | # ... type `` `bar` `` ...
1287 | #
1288 | # Turns to:
1289 | #
1290 | # ... type `bar`
...
1291 | return self._code_span_re.sub(self._code_span_sub, text)
1292 |
1293 | def _encode_code(self, text):
1294 | """Encode/escape certain characters inside Markdown code runs.
1295 | The point is that in code, these characters are literals,
1296 | and lose their special Markdown meanings.
1297 | """
1298 | replacements = [
1299 | # Encode all ampersands; HTML entities are not
1300 | # entities within a Markdown code span.
1301 | ('&', '&'),
1302 | # Do the angle bracket song and dance:
1303 | ('<', '<'),
1304 | ('>', '>'),
1305 | # Now, escape characters that are magic in Markdown:
1306 | ('*', g_escape_table['*']),
1307 | ('_', g_escape_table['_']),
1308 | ('{', g_escape_table['{']),
1309 | ('}', g_escape_table['}']),
1310 | ('[', g_escape_table['[']),
1311 | (']', g_escape_table[']']),
1312 | ('\\', g_escape_table['\\']),
1313 | ]
1314 | for before, after in replacements:
1315 | text = text.replace(before, after)
1316 | return text
1317 |
1318 | _strong_re = re.compile(r"(\*\*|__)(?=\S)(.+?[*_]*)(?<=\S)\1", re.S)
1319 | _em_re = re.compile(r"(\*|_)(?=\S)(.+?)(?<=\S)\1", re.S)
1320 | _code_friendly_strong_re = re.compile(r"\*\*(?=\S)(.+?[*_]*)(?<=\S)\*\*", re.S)
1321 | _code_friendly_em_re = re.compile(r"\*(?=\S)(.+?)(?<=\S)\*", re.S)
1322 | def _do_italics_and_bold(self, text):
1323 | # must go first:
1324 | if "code-friendly" in self.extras:
1325 | text = self._code_friendly_strong_re.sub(r"\1", text)
1326 | text = self._code_friendly_em_re.sub(r"\1", text)
1327 | else:
1328 | text = self._strong_re.sub(r"\2", text)
1329 | text = self._em_re.sub(r"\2", text)
1330 | return text
1331 |
1332 |
1333 | _block_quote_re = re.compile(r'''
1334 | ( # Wrap whole match in \1
1335 | (
1336 | ^[ \t]*>[ \t]? # '>' at the start of a line
1337 | .+\n # rest of the first line
1338 | (.+\n)* # subsequent consecutive lines
1339 | \n* # blanks
1340 | )+
1341 | )
1342 | ''', re.M | re.X)
1343 | _bq_one_level_re = re.compile('^[ \t]*>[ \t]?', re.M);
1344 |
1345 | _html_pre_block_re = re.compile(r'(\s*.+?
)', re.S)
1346 | def _dedent_two_spaces_sub(self, match):
1347 | return re.sub(r'(?m)^ ', '', match.group(1))
1348 |
1349 | def _block_quote_sub(self, match):
1350 | bq = match.group(1)
1351 | bq = self._bq_one_level_re.sub('', bq) # trim one level of quoting
1352 | bq = self._ws_only_line_re.sub('', bq) # trim whitespace-only lines
1353 | bq = self._run_block_gamut(bq) # recurse
1354 |
1355 | bq = re.sub('(?m)^', ' ', bq)
1356 | # These leading spaces screw with content, so we need to fix that:
1357 | bq = self._html_pre_block_re.sub(self._dedent_two_spaces_sub, bq)
1358 |
1359 | return "\n%s\n
\n\n" % bq
1360 |
1361 | def _do_block_quotes(self, text):
1362 | if '>' not in text:
1363 | return text
1364 | return self._block_quote_re.sub(self._block_quote_sub, text)
1365 |
1366 | def _form_paragraphs(self, text):
1367 | # Strip leading and trailing lines:
1368 | text = text.strip('\n')
1369 |
1370 | # Wrap tags.
1371 | grafs = re.split(r"\n{2,}", text)
1372 | for i, graf in enumerate(grafs):
1373 | if graf in self.html_blocks:
1374 | # Unhashify HTML blocks
1375 | grafs[i] = self.html_blocks[graf]
1376 | else:
1377 | # Wrap
tags.
1378 | graf = self._run_span_gamut(graf)
1379 | grafs[i] = "
" + graf.lstrip(" \t") + "
"
1380 |
1381 | return "\n\n".join(grafs)
1382 |
1383 | def _add_footnotes(self, text):
1384 | if self.footnotes:
1385 | footer = [
1386 | '')
1407 | return text + '\n\n' + '\n'.join(footer)
1408 | else:
1409 | return text
1410 |
1411 | # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1412 | # http://bumppo.net/projects/amputator/
1413 | _ampersand_re = re.compile(r'&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)')
1414 | _naked_lt_re = re.compile(r'<(?![a-z/?\$!])', re.I)
1415 | _naked_gt_re = re.compile(r'''(?''', re.I)
1416 |
1417 | def _encode_amps_and_angles(self, text):
1418 | # Smart processing for ampersands and angle brackets that need
1419 | # to be encoded.
1420 | text = self._ampersand_re.sub('&', text)
1421 |
1422 | # Encode naked <'s
1423 | text = self._naked_lt_re.sub('<', text)
1424 |
1425 | # Encode naked >'s
1426 | # Note: Other markdown implementations (e.g. Markdown.pl, PHP
1427 | # Markdown) don't do this.
1428 | text = self._naked_gt_re.sub('>', text)
1429 | return text
1430 |
1431 | def _encode_backslash_escapes(self, text):
1432 | for ch, escape in g_escape_table.items():
1433 | text = text.replace("\\"+ch, escape)
1434 | return text
1435 |
1436 | _auto_link_re = re.compile(r'<((https?|ftp):[^\'">\s]+)>', re.I)
1437 | def _auto_link_sub(self, match):
1438 | g1 = match.group(1)
1439 | return '%s' % (g1, g1)
1440 |
1441 | _auto_email_link_re = re.compile(r"""
1442 | <
1443 | (?:mailto:)?
1444 | (
1445 | [-.\w]+
1446 | \@
1447 | [-\w]+(\.[-\w]+)*\.[a-z]+
1448 | )
1449 | >
1450 | """, re.I | re.X | re.U)
1451 | def _auto_email_link_sub(self, match):
1452 | return self._encode_email_address(
1453 | self._unescape_special_chars(match.group(1)))
1454 |
1455 | def _do_auto_links(self, text):
1456 | text = self._auto_link_re.sub(self._auto_link_sub, text)
1457 | text = self._auto_email_link_re.sub(self._auto_email_link_sub, text)
1458 | return text
1459 |
1460 | def _encode_email_address(self, addr):
1461 | # Input: an email address, e.g. "foo@example.com"
1462 | #
1463 | # Output: the email address as a mailto link, with each character
1464 | # of the address encoded as either a decimal or hex entity, in
1465 | # the hopes of foiling most address harvesting spam bots. E.g.:
1466 | #
1467 | # foo
1469 | # @example.com
1470 | #
1471 | # Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
1472 | # mailing list:
1473 | chars = [_xml_encode_email_char_at_random(ch)
1474 | for ch in "mailto:" + addr]
1475 | # Strip the mailto: from the visible part.
1476 | addr = '%s' \
1477 | % (''.join(chars), ''.join(chars[7:]))
1478 | return addr
1479 |
1480 | def _do_link_patterns(self, text):
1481 | """Caveat emptor: there isn't much guarding against link
1482 | patterns being formed inside other standard Markdown links, e.g.
1483 | inside a [link def][like this].
1484 |
1485 | Dev Notes: *Could* consider prefixing regexes with a negative
1486 | lookbehind assertion to attempt to guard against this.
1487 | """
1488 | link_from_hash = {}
1489 | for regex, repl in self.link_patterns:
1490 | replacements = []
1491 | for match in regex.finditer(text):
1492 | if hasattr(repl, "__call__"):
1493 | href = repl(match)
1494 | else:
1495 | href = match.expand(repl)
1496 | replacements.append((match.span(), href))
1497 | for (start, end), href in reversed(replacements):
1498 | escaped_href = (
1499 | href.replace('"', '"') # b/c of attr quote
1500 | # To avoid markdown and :
1501 | .replace('*', g_escape_table['*'])
1502 | .replace('_', g_escape_table['_']))
1503 | link = '%s' % (escaped_href, text[start:end])
1504 | hash = md5(link).hexdigest()
1505 | link_from_hash[hash] = link
1506 | text = text[:start] + hash + text[end:]
1507 | for hash, link in link_from_hash.items():
1508 | text = text.replace(hash, link)
1509 | return text
1510 |
1511 | def _unescape_special_chars(self, text):
1512 | # Swap back in all the special characters we've hidden.
1513 | for ch, hash in g_escape_table.items():
1514 | text = text.replace(hash, ch)
1515 | return text
1516 |
1517 | def _outdent(self, text):
1518 | # Remove one level of line-leading tabs or spaces
1519 | return self._outdent_re.sub('', text)
1520 |
1521 |
1522 | class MarkdownWithExtras(Markdown):
1523 | """A markdowner class that enables most extras:
1524 |
1525 | - footnotes
1526 | - code-color (only has effect if 'pygments' Python module on path)
1527 |
1528 | These are not included:
1529 | - pyshell (specific to Python-related documenting)
1530 | - code-friendly (because it *disables* part of the syntax)
1531 | - link-patterns (because you need to specify some actual
1532 | link-patterns anyway)
1533 | """
1534 | extras = ["footnotes", "code-color"]
1535 |
1536 |
1537 | #---- internal support functions
1538 |
1539 | # From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
1540 | def _curry(*args, **kwargs):
1541 | function, args = args[0], args[1:]
1542 | def result(*rest, **kwrest):
1543 | combined = kwargs.copy()
1544 | combined.update(kwrest)
1545 | return function(*args + rest, **combined)
1546 | return result
1547 |
1548 | # Recipe: regex_from_encoded_pattern (1.0)
1549 | def _regex_from_encoded_pattern(s):
1550 | """'foo' -> re.compile(re.escape('foo'))
1551 | '/foo/' -> re.compile('foo')
1552 | '/foo/i' -> re.compile('foo', re.I)
1553 | """
1554 | if s.startswith('/') and s.rfind('/') != 0:
1555 | # Parse it: /PATTERN/FLAGS
1556 | idx = s.rfind('/')
1557 | pattern, flags_str = s[1:idx], s[idx+1:]
1558 | flag_from_char = {
1559 | "i": re.IGNORECASE,
1560 | "l": re.LOCALE,
1561 | "s": re.DOTALL,
1562 | "m": re.MULTILINE,
1563 | "u": re.UNICODE,
1564 | }
1565 | flags = 0
1566 | for char in flags_str:
1567 | try:
1568 | flags |= flag_from_char[char]
1569 | except KeyError:
1570 | raise ValueError("unsupported regex flag: '%s' in '%s' "
1571 | "(must be one of '%s')"
1572 | % (char, s, ''.join(flag_from_char.keys())))
1573 | return re.compile(s[1:idx], flags)
1574 | else: # not an encoded regex
1575 | return re.compile(re.escape(s))
1576 |
1577 | # Recipe: dedent (0.1.2)
1578 | def _dedentlines(lines, tabsize=8, skip_first_line=False):
1579 | """_dedentlines(lines, tabsize=8, skip_first_line=False) -> dedented lines
1580 |
1581 | "lines" is a list of lines to dedent.
1582 | "tabsize" is the tab width to use for indent width calculations.
1583 | "skip_first_line" is a boolean indicating if the first line should
1584 | be skipped for calculating the indent width and for dedenting.
1585 | This is sometimes useful for docstrings and similar.
1586 |
1587 | Same as dedent() except operates on a sequence of lines. Note: the
1588 | lines list is modified **in-place**.
1589 | """
1590 | DEBUG = False
1591 | if DEBUG:
1592 | print "dedent: dedent(..., tabsize=%d, skip_first_line=%r)"\
1593 | % (tabsize, skip_first_line)
1594 | indents = []
1595 | margin = None
1596 | for i, line in enumerate(lines):
1597 | if i == 0 and skip_first_line: continue
1598 | indent = 0
1599 | for ch in line:
1600 | if ch == ' ':
1601 | indent += 1
1602 | elif ch == '\t':
1603 | indent += tabsize - (indent % tabsize)
1604 | elif ch in '\r\n':
1605 | continue # skip all-whitespace lines
1606 | else:
1607 | break
1608 | else:
1609 | continue # skip all-whitespace lines
1610 | if DEBUG: print "dedent: indent=%d: %r" % (indent, line)
1611 | if margin is None:
1612 | margin = indent
1613 | else:
1614 | margin = min(margin, indent)
1615 | if DEBUG: print "dedent: margin=%r" % margin
1616 |
1617 | if margin is not None and margin > 0:
1618 | for i, line in enumerate(lines):
1619 | if i == 0 and skip_first_line: continue
1620 | removed = 0
1621 | for j, ch in enumerate(line):
1622 | if ch == ' ':
1623 | removed += 1
1624 | elif ch == '\t':
1625 | removed += tabsize - (removed % tabsize)
1626 | elif ch in '\r\n':
1627 | if DEBUG: print "dedent: %r: EOL -> strip up to EOL" % line
1628 | lines[i] = lines[i][j:]
1629 | break
1630 | else:
1631 | raise ValueError("unexpected non-whitespace char %r in "
1632 | "line %r while removing %d-space margin"
1633 | % (ch, line, margin))
1634 | if DEBUG:
1635 | print "dedent: %r: %r -> removed %d/%d"\
1636 | % (line, ch, removed, margin)
1637 | if removed == margin:
1638 | lines[i] = lines[i][j+1:]
1639 | break
1640 | elif removed > margin:
1641 | lines[i] = ' '*(removed-margin) + lines[i][j+1:]
1642 | break
1643 | else:
1644 | if removed:
1645 | lines[i] = lines[i][removed:]
1646 | return lines
1647 |
1648 | def _dedent(text, tabsize=8, skip_first_line=False):
1649 | """_dedent(text, tabsize=8, skip_first_line=False) -> dedented text
1650 |
1651 | "text" is the text to dedent.
1652 | "tabsize" is the tab width to use for indent width calculations.
1653 | "skip_first_line" is a boolean indicating if the first line should
1654 | be skipped for calculating the indent width and for dedenting.
1655 | This is sometimes useful for docstrings and similar.
1656 |
1657 | textwrap.dedent(s), but don't expand tabs to spaces
1658 | """
1659 | lines = text.splitlines(1)
1660 | _dedentlines(lines, tabsize=tabsize, skip_first_line=skip_first_line)
1661 | return ''.join(lines)
1662 |
1663 |
1664 | class _memoized(object):
1665 | """Decorator that caches a function's return value each time it is called.
1666 | If called later with the same arguments, the cached value is returned, and
1667 | not re-evaluated.
1668 |
1669 | http://wiki.python.org/moin/PythonDecoratorLibrary
1670 | """
1671 | def __init__(self, func):
1672 | self.func = func
1673 | self.cache = {}
1674 | def __call__(self, *args):
1675 | try:
1676 | return self.cache[args]
1677 | except KeyError:
1678 | self.cache[args] = value = self.func(*args)
1679 | return value
1680 | except TypeError:
1681 | # uncachable -- for instance, passing a list as an argument.
1682 | # Better to not cache than to blow up entirely.
1683 | return self.func(*args)
1684 | def __repr__(self):
1685 | """Return the function's docstring."""
1686 | return self.func.__doc__
1687 |
1688 |
1689 | def _xml_oneliner_re_from_tab_width(tab_width):
1690 | """Standalone XML processing instruction regex."""
1691 | return re.compile(r"""
1692 | (?:
1693 | (?<=\n\n) # Starting after a blank line
1694 | | # or
1695 | \A\n? # the beginning of the doc
1696 | )
1697 | ( # save in $1
1698 | [ ]{0,%d}
1699 | (?:
1700 | <\?\w+\b\s+.*?\?> # XML processing instruction
1701 | |
1702 | <\w+:\w+\b\s+.*?/> # namespaced single tag
1703 | )
1704 | [ \t]*
1705 | (?=\n{2,}|\Z) # followed by a blank line or end of document
1706 | )
1707 | """ % (tab_width - 1), re.X)
1708 | _xml_oneliner_re_from_tab_width = _memoized(_xml_oneliner_re_from_tab_width)
1709 |
1710 | def _hr_tag_re_from_tab_width(tab_width):
1711 | return re.compile(r"""
1712 | (?:
1713 | (?<=\n\n) # Starting after a blank line
1714 | | # or
1715 | \A\n? # the beginning of the doc
1716 | )
1717 | ( # save in \1
1718 | [ ]{0,%d}
1719 | <(hr) # start tag = \2
1720 | \b # word break
1721 | ([^<>])*? #
1722 | /?> # the matching end tag
1723 | [ \t]*
1724 | (?=\n{2,}|\Z) # followed by a blank line or end of document
1725 | )
1726 | """ % (tab_width - 1), re.X)
1727 | _hr_tag_re_from_tab_width = _memoized(_hr_tag_re_from_tab_width)
1728 |
1729 |
1730 | def _xml_encode_email_char_at_random(ch):
1731 | r = random()
1732 | # Roughly 10% raw, 45% hex, 45% dec.
1733 | # '@' *must* be encoded. I [John Gruber] insist.
1734 | # Issue 26: '_' must be encoded.
1735 | if r > 0.9 and ch not in "@_":
1736 | return ch
1737 | elif r < 0.45:
1738 | # The [1:] is to drop leading '0': 0x63 -> x63
1739 | return '%s;' % hex(ord(ch))[1:]
1740 | else:
1741 | return '%s;' % ord(ch)
1742 |
1743 | def _hash_text(text):
1744 | return 'md5:'+md5(text.encode("utf-8")).hexdigest()
1745 |
1746 |
1747 | #---- mainline
1748 |
1749 | class _NoReflowFormatter(optparse.IndentedHelpFormatter):
1750 | """An optparse formatter that does NOT reflow the description."""
1751 | def format_description(self, description):
1752 | return description or ""
1753 |
1754 | def _test():
1755 | import doctest
1756 | doctest.testmod()
1757 |
1758 | def main(argv=None):
1759 | if argv is None:
1760 | argv = sys.argv
1761 | if not logging.root.handlers:
1762 | logging.basicConfig()
1763 |
1764 | usage = "usage: %prog [PATHS...]"
1765 | version = "%prog "+__version__
1766 | parser = optparse.OptionParser(prog="markdown2", usage=usage,
1767 | version=version, description=cmdln_desc,
1768 | formatter=_NoReflowFormatter())
1769 | parser.add_option("-v", "--verbose", dest="log_level",
1770 | action="store_const", const=logging.DEBUG,
1771 | help="more verbose output")
1772 | parser.add_option("--encoding",
1773 | help="specify encoding of text content")
1774 | parser.add_option("--html4tags", action="store_true", default=False,
1775 | help="use HTML 4 style for empty element tags")
1776 | parser.add_option("-s", "--safe", metavar="MODE", dest="safe_mode",
1777 | help="sanitize literal HTML: 'escape' escapes "
1778 | "HTML meta chars, 'replace' replaces with an "
1779 | "[HTML_REMOVED] note")
1780 | parser.add_option("-x", "--extras", action="append",
1781 | help="Turn on specific extra features (not part of "
1782 | "the core Markdown spec). Supported values: "
1783 | "'code-friendly' disables _/__ for emphasis; "
1784 | "'code-color' adds code-block syntax coloring; "
1785 | "'link-patterns' adds auto-linking based on patterns; "
1786 | "'footnotes' adds the footnotes syntax;"
1787 | "'xml' passes one-liner processing instructions and namespaced XML tags;"
1788 | "'pyshell' to put unindented Python interactive shell sessions in a block.")
1789 | parser.add_option("--use-file-vars",
1790 | help="Look for and use Emacs-style 'markdown-extras' "
1791 | "file var to turn on extras. See "
1792 | ".")
1793 | parser.add_option("--link-patterns-file",
1794 | help="path to a link pattern file")
1795 | parser.add_option("--self-test", action="store_true",
1796 | help="run internal self-tests (some doctests)")
1797 | parser.add_option("--compare", action="store_true",
1798 | help="run against Markdown.pl as well (for testing)")
1799 | parser.set_defaults(log_level=logging.INFO, compare=False,
1800 | encoding="utf-8", safe_mode=None, use_file_vars=False)
1801 | opts, paths = parser.parse_args()
1802 | log.setLevel(opts.log_level)
1803 |
1804 | if opts.self_test:
1805 | return _test()
1806 |
1807 | if opts.extras:
1808 | extras = {}
1809 | for s in opts.extras:
1810 | splitter = re.compile("[,;: ]+")
1811 | for e in splitter.split(s):
1812 | if '=' in e:
1813 | ename, earg = e.split('=', 1)
1814 | try:
1815 | earg = int(earg)
1816 | except ValueError:
1817 | pass
1818 | else:
1819 | ename, earg = e, None
1820 | extras[ename] = earg
1821 | else:
1822 | extras = None
1823 |
1824 | if opts.link_patterns_file:
1825 | link_patterns = []
1826 | f = open(opts.link_patterns_file)
1827 | try:
1828 | for i, line in enumerate(f.readlines()):
1829 | if not line.strip(): continue
1830 | if line.lstrip().startswith("#"): continue
1831 | try:
1832 | pat, href = line.rstrip().rsplit(None, 1)
1833 | except ValueError:
1834 | raise MarkdownError("%s:%d: invalid link pattern line: %r"
1835 | % (opts.link_patterns_file, i+1, line))
1836 | link_patterns.append(
1837 | (_regex_from_encoded_pattern(pat), href))
1838 | finally:
1839 | f.close()
1840 | else:
1841 | link_patterns = None
1842 |
1843 | from os.path import join, dirname, abspath, exists
1844 | markdown_pl = join(dirname(dirname(abspath(__file__))), "test",
1845 | "Markdown.pl")
1846 | for path in paths:
1847 | if opts.compare:
1848 | print "==== Markdown.pl ===="
1849 | perl_cmd = 'perl %s "%s"' % (markdown_pl, path)
1850 | o = os.popen(perl_cmd)
1851 | perl_html = o.read()
1852 | o.close()
1853 | sys.stdout.write(perl_html)
1854 | print "==== markdown2.py ===="
1855 | html = markdown_path(path, encoding=opts.encoding,
1856 | html4tags=opts.html4tags,
1857 | safe_mode=opts.safe_mode,
1858 | extras=extras, link_patterns=link_patterns,
1859 | use_file_vars=opts.use_file_vars)
1860 | sys.stdout.write(
1861 | html.encode(sys.stdout.encoding or "utf-8", 'xmlcharrefreplace'))
1862 | if opts.compare:
1863 | test_dir = join(dirname(dirname(abspath(__file__))), "test")
1864 | if exists(join(test_dir, "test_markdown2.py")):
1865 | sys.path.insert(0, test_dir)
1866 | from test_markdown2 import norm_html_from_html
1867 | norm_html = norm_html_from_html(html)
1868 | norm_perl_html = norm_html_from_html(perl_html)
1869 | else:
1870 | norm_html = html
1871 | norm_perl_html = perl_html
1872 | print "==== match? %r ====" % (norm_perl_html == norm_html)
1873 |
1874 |
1875 | if __name__ == "__main__":
1876 | sys.exit( main(sys.argv) )
1877 |
1878 |
--------------------------------------------------------------------------------
/libs/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from hashlib import sha1
5 | import random
6 |
7 |
8 | def hexuserpass(password):
9 | """
10 | 加密使用者发布代码时的密码,所以使用最简单的加密方法
11 | """
12 | enpass = sha1(password.encode('utf-8')).hexdigest()
13 | return enpass
14 |
15 |
16 | def checkuserpass(passwd, enpass):
17 | password = hexuserpass(passwd)
18 | return (password == enpass)
19 |
20 |
21 | def hexpassword(password):
22 | """
23 | 加密管理员密码,就目前来说,这个加密强度也太弱了,可以考虑使用 `pbkdf2` 加密方法
24 | """
25 | seed = "1234567890abcdefghijklmnopqrstuvwxyz \
26 | ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-"
27 | sa = []
28 | for i in range(8):
29 | sa.append(random.choice(seed))
30 | salt = ''.join(sa)
31 | enpass = sha1(sha1((salt + password).encode('utf-8')).hexdigest().encode('utf-8')).hexdigest()
32 | return str(salt) + '$' + str(enpass)
33 |
34 |
35 | def checkpassword(passwd, enpass):
36 | salt = enpass[:8]
37 | password = sha1(sha1((salt + passwd).encode('utf-8')).hexdigest().encode('utf-8')).hexdigest()
38 | p = str(salt) + '$' + str(password)
39 | return (p == enpass)
40 |
--------------------------------------------------------------------------------
/settings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import os.path
5 | import sae.const
6 |
7 | # 分页时每页的条目数
8 | NAVNUM = 8
9 |
10 | settings = {
11 | "sitename": "Code Share", # 设置为你的站点名
12 | "template_path": os.path.join(os.path.dirname(__file__), "templates"),
13 | "static_path": os.path.join(os.path.dirname(__file__), "static"),
14 | "xsrf_cookies": True,
15 | # 设置为随机的一串字符,千万不要使用现在这个
16 | "cookie_secret": "11oETzKXQAGaYdkL5gEmGeJJFuYh78768945$6P1o/Vo=",
17 | "login_url": "/auth/login",
18 | "autoescape": None,
19 | "debug": False,
20 | }
21 |
22 | #数据库设置
23 | db = {
24 | "host": sae.const.MYSQL_HOST,
25 | "db": sae.const.MYSQL_DB,
26 | "port": sae.const.MYSQL_PORT,
27 | "user": sae.const.MYSQL_USER,
28 | "password": sae.const.MYSQL_PASS,
29 | }
30 |
--------------------------------------------------------------------------------
/static/blog.css:
--------------------------------------------------------------------------------
1 |
2 | body{
3 | background-color: #eee;
4 | }
5 |
6 | div.container{
7 | width:840px;
8 | }
9 |
10 | .header{
11 | background-color: #fff;
12 | margin:0 10px 20px;
13 | }
14 |
15 | .header,
16 | .header a{
17 | color: white;
18 | }
19 | .header h1{
20 | font-size:20px;
21 | padding:5px;
22 | margin:0;
23 | }
24 | .header h1 a {
25 | text-decoration: none;
26 | }
27 | .hleft{
28 | background-color: #0064cd;
29 | float:left;
30 | }
31 | .hleft:hover{
32 | background-color: #db4937;
33 | }
34 |
35 | .hright{
36 | float:right;
37 | padding:5px;
38 | }
39 | #content{
40 | background-color: #fff;
41 | padding: 20px;
42 | margin: 0 10px 10px;
43 | -moz-border-radius: 6px;
44 | -webkit-border-top-left-radius: 6px;
45 | -webkit-border-top-right-radius: 6px;
46 | -webkit-border-bottom-left-radius: 6px;
47 | -webkit-border-bottom-right-radius: 6px;
48 | border-radius: 6px;
49 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15);
50 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15);
51 | box-shadow: 0 1px 2px rgba(0,0,0,.15);
52 | }
53 |
54 | #footer p{
55 | text-align: center;
56 | }
57 |
58 | .entry h1 a{
59 | color: black;
60 | text-decoration: none;
61 | }
62 |
63 | .entry{
64 | margin-bottom: 2em;
65 | }
66 |
67 | .entry p {
68 | margin: 0;
69 | margin-bottom: 1em;
70 | }
71 |
72 | .entry .body{
73 | margin-top: 1em;
74 | line-height: 16pt;
75 | }
76 | .title{
77 | float:left;
78 | }
79 | .title h2{
80 | font-weight:normal;
81 | }
82 | .delete{
83 | float:right;
84 | margin-left:20px;
85 | }
86 | .box{
87 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
88 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
89 | box-shadow:0 1px 3px rgba(0, 0, 0, 0.2);
90 | -moz-border-radius: 5px;
91 | -webkit-border-top-left-radius: 5px;
92 | -webkit-border-top-right-radius: 5px;
93 | -webkit-border-bottom-left-radius: 5px;
94 | -webkit-border-bottom-right-radius: 5px;
95 | border-radius: 5px;
96 | }
97 | .clearfix:after{
98 | content: ".";
99 | visibility: hidden;
100 | display: block;
101 | height: 0;
102 | clear: both;
103 | }
--------------------------------------------------------------------------------
/static/bootstrap-modal.js:
--------------------------------------------------------------------------------
1 | /* =========================================================
2 | * bootstrap-modal.js v1.4.0
3 | * http://twitter.github.com/bootstrap/javascript.html#modal
4 | * =========================================================
5 | * Copyright 2011 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================= */
19 |
20 |
21 | !function( $ ){
22 |
23 | "use strict"
24 |
25 | /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
26 | * ======================================================= */
27 |
28 | var transitionEnd
29 |
30 | $(document).ready(function () {
31 |
32 | $.support.transition = (function () {
33 | var thisBody = document.body || document.documentElement
34 | , thisStyle = thisBody.style
35 | , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
36 | return support
37 | })()
38 |
39 | // set CSS transition event type
40 | if ( $.support.transition ) {
41 | transitionEnd = "TransitionEnd"
42 | if ( $.browser.webkit ) {
43 | transitionEnd = "webkitTransitionEnd"
44 | } else if ( $.browser.mozilla ) {
45 | transitionEnd = "transitionend"
46 | } else if ( $.browser.opera ) {
47 | transitionEnd = "oTransitionEnd"
48 | }
49 | }
50 |
51 | })
52 |
53 |
54 | /* MODAL PUBLIC CLASS DEFINITION
55 | * ============================= */
56 |
57 | var Modal = function ( content, options ) {
58 | this.settings = $.extend({}, $.fn.modal.defaults, options)
59 | this.$element = $(content)
60 | .delegate('.close', 'click.modal', $.proxy(this.hide, this))
61 |
62 | if ( this.settings.show ) {
63 | this.show()
64 | }
65 |
66 | return this
67 | }
68 |
69 | Modal.prototype = {
70 |
71 | toggle: function () {
72 | return this[!this.isShown ? 'show' : 'hide']()
73 | }
74 |
75 | , show: function () {
76 | var that = this
77 | this.isShown = true
78 | this.$element.trigger('show')
79 |
80 | escape.call(this)
81 | backdrop.call(this, function () {
82 | var transition = $.support.transition && that.$element.hasClass('fade')
83 |
84 | that.$element
85 | .appendTo(document.body)
86 | .show()
87 |
88 | if (transition) {
89 | that.$element[0].offsetWidth // force reflow
90 | }
91 |
92 | that.$element.addClass('in')
93 |
94 | transition ?
95 | that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) :
96 | that.$element.trigger('shown')
97 |
98 | })
99 |
100 | return this
101 | }
102 |
103 | , hide: function (e) {
104 | e && e.preventDefault()
105 |
106 | if ( !this.isShown ) {
107 | return this
108 | }
109 |
110 | var that = this
111 | this.isShown = false
112 |
113 | escape.call(this)
114 |
115 | this.$element
116 | .trigger('hide')
117 | .removeClass('in')
118 |
119 | $.support.transition && this.$element.hasClass('fade') ?
120 | hideWithTransition.call(this) :
121 | hideModal.call(this)
122 |
123 | return this
124 | }
125 |
126 | }
127 |
128 |
129 | /* MODAL PRIVATE METHODS
130 | * ===================== */
131 |
132 | function hideWithTransition() {
133 | // firefox drops transitionEnd events :{o
134 | var that = this
135 | , timeout = setTimeout(function () {
136 | that.$element.unbind(transitionEnd)
137 | hideModal.call(that)
138 | }, 500)
139 |
140 | this.$element.one(transitionEnd, function () {
141 | clearTimeout(timeout)
142 | hideModal.call(that)
143 | })
144 | }
145 |
146 | function hideModal (that) {
147 | this.$element
148 | .hide()
149 | .trigger('hidden')
150 |
151 | backdrop.call(this)
152 | }
153 |
154 | function backdrop ( callback ) {
155 | var that = this
156 | , animate = this.$element.hasClass('fade') ? 'fade' : ''
157 | if ( this.isShown && this.settings.backdrop ) {
158 | var doAnimate = $.support.transition && animate
159 |
160 | this.$backdrop = $('')
161 | .appendTo(document.body)
162 |
163 | if ( this.settings.backdrop != 'static' ) {
164 | this.$backdrop.click($.proxy(this.hide, this))
165 | }
166 |
167 | if ( doAnimate ) {
168 | this.$backdrop[0].offsetWidth // force reflow
169 | }
170 |
171 | this.$backdrop.addClass('in')
172 |
173 | doAnimate ?
174 | this.$backdrop.one(transitionEnd, callback) :
175 | callback()
176 |
177 | } else if ( !this.isShown && this.$backdrop ) {
178 | this.$backdrop.removeClass('in')
179 |
180 | $.support.transition && this.$element.hasClass('fade')?
181 | this.$backdrop.one(transitionEnd, $.proxy(removeBackdrop, this)) :
182 | removeBackdrop.call(this)
183 |
184 | } else if ( callback ) {
185 | callback()
186 | }
187 | }
188 |
189 | function removeBackdrop() {
190 | this.$backdrop.remove()
191 | this.$backdrop = null
192 | }
193 |
194 | function escape() {
195 | var that = this
196 | if ( this.isShown && this.settings.keyboard ) {
197 | $(document).bind('keyup.modal', function ( e ) {
198 | if ( e.which == 27 ) {
199 | that.hide()
200 | }
201 | })
202 | } else if ( !this.isShown ) {
203 | $(document).unbind('keyup.modal')
204 | }
205 | }
206 |
207 |
208 | /* MODAL PLUGIN DEFINITION
209 | * ======================= */
210 |
211 | $.fn.modal = function ( options ) {
212 | var modal = this.data('modal')
213 |
214 | if (!modal) {
215 |
216 | if (typeof options == 'string') {
217 | options = {
218 | show: /show|toggle/.test(options)
219 | }
220 | }
221 |
222 | return this.each(function () {
223 | $(this).data('modal', new Modal(this, options))
224 | })
225 | }
226 |
227 | if ( options === true ) {
228 | return modal
229 | }
230 |
231 | if ( typeof options == 'string' ) {
232 | modal[options]()
233 | } else if ( modal ) {
234 | modal.toggle()
235 | }
236 |
237 | return this
238 | }
239 |
240 | $.fn.modal.Modal = Modal
241 |
242 | $.fn.modal.defaults = {
243 | backdrop: false
244 | , keyboard: false
245 | , show: false
246 | }
247 |
248 |
249 | /* MODAL DATA- IMPLEMENTATION
250 | * ========================== */
251 |
252 | $(document).ready(function () {
253 | $('body').delegate('[data-controls-modal]', 'click', function (e) {
254 | e.preventDefault()
255 | var $this = $(this).data('show', true)
256 | $('#' + $this.attr('data-controls-modal')).modal( $this.data() )
257 | })
258 | })
259 |
260 | }( window.jQuery || window.ender );
261 |
--------------------------------------------------------------------------------
/static/bootstrap.min.css:
--------------------------------------------------------------------------------
1 | html,body{margin:0;padding:0;}
2 | h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;}
3 | table{border-collapse:collapse;border-spacing:0;}
4 | ol,ul{list-style:none;}
5 | q:before,q:after,blockquote:before,blockquote:after{content:"";}
6 | html{overflow-y:scroll;font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
7 | a:focus{outline:thin dotted;}
8 | a:hover,a:active{outline:0;}
9 | article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
10 | audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
11 | audio:not([controls]){display:none;}
12 | sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}
13 | sup{top:-0.5em;}
14 | sub{bottom:-0.25em;}
15 | img{border:0;-ms-interpolation-mode:bicubic;}
16 | button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;}
17 | button,input{line-height:normal;*overflow:visible;}
18 | button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
19 | button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
20 | input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
21 | input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
22 | textarea{overflow:auto;vertical-align:top;}
23 | body{background-color:#ffffff;margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;color:#404040;}
24 | .container{width:940px;margin-left:auto;margin-right:auto;zoom:1;}.container:before,.container:after{display:table;content:"";zoom:1;}
25 | .container:after{clear:both;}
26 | .container-fluid{position:relative;min-width:940px;padding-left:20px;padding-right:20px;zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";zoom:1;}
27 | .container-fluid:after{clear:both;}
28 | .container-fluid>.sidebar{position:absolute;top:0;left:20px;width:220px;}
29 | .container-fluid>.content{margin-left:240px;}
30 | a{color:#0069d6;text-decoration:none;line-height:inherit;font-weight:inherit;}a:hover{color:#00438a;text-decoration:underline;}
31 | .pull-right{float:right;}
32 | .pull-left{float:left;}
33 | .hide{display:none;}
34 | .show{display:block;}
35 | .row{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;}
36 | .row:after{clear:both;}
37 | .row>[class*="span"]{display:inline;float:left;margin-left:20px;}
38 |
39 | .span4{width:220px;}
40 |
41 | .span10{width:580px;}
42 |
43 | .row>.offset1{margin-left:80px;}
44 | .row>.offset2{margin-left:140px;}
45 | .row>.offset3{margin-left:200px;}
46 | .row>.offset4{margin-left:260px;}
47 | .row>.offset5{margin-left:320px;}
48 | .row>.offset6{margin-left:380px;}
49 | .row>.offset7{margin-left:440px;}
50 | .row>.offset8{margin-left:500px;}
51 | .row>.offset9{margin-left:560px;}
52 | .row>.offset10{margin-left:620px;}
53 | .row>.offset11{margin-left:680px;}
54 | .row>.offset12{margin-left:740px;}
55 | .span-one-third{width:300px;}
56 | .span-two-thirds{width:620px;}
57 | .row>.offset-one-third{margin-left:340px;}
58 | .row>.offset-two-thirds{margin-left:660px;}
59 | p{font-size:13px;font-weight:normal;line-height:18px;margin-bottom:9px;}p small{font-size:11px;color:#bfbfbf;}
60 | h1,h2,h3,h4,h5,h6{font-weight:bold;color:#404040;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#bfbfbf;}
61 | h1{margin-bottom:18px;font-size:30px;line-height:36px;}h1 small{font-size:18px;}
62 | h2{font-size:24px;line-height:36px;}h2 small{font-size:14px;}
63 | h3,h4,h5,h6{line-height:36px;}
64 | h3{font-size:18px;}h3 small{font-size:14px;}
65 | h4{font-size:16px;}h4 small{font-size:12px;}
66 | h5{font-size:14px;}
67 | h6{font-size:13px;color:#bfbfbf;text-transform:uppercase;}
68 | ul,ol{margin:0 0 18px 25px;}
69 | ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
70 | ul{list-style:disc;}
71 | ol{list-style:decimal;}
72 | li{line-height:18px;color:#808080;}
73 | ul.unstyled{list-style:none;margin-left:0;}
74 | dl{margin-bottom:18px;}dl dt,dl dd{line-height:18px;}
75 | dl dt{font-weight:bold;}
76 | dl dd{margin-left:9px;}
77 | hr{margin:20px 0 19px;border:0;border-bottom:1px solid #eee;}
78 | strong{font-style:inherit;font-weight:bold;}
79 | em{font-style:italic;font-weight:inherit;line-height:inherit;}
80 | .muted{color:#bfbfbf;}
81 | blockquote{margin-bottom:18px;border-left:5px solid #eee;padding-left:15px;}blockquote p{font-size:14px;font-weight:300;line-height:18px;margin-bottom:0;}
82 | blockquote small{display:block;font-size:12px;font-weight:300;line-height:18px;color:#bfbfbf;}blockquote small:before{content:'\2014 \00A0';}
83 | address{display:block;line-height:18px;margin-bottom:18px;}
84 | code,pre{padding:0 3px 2px;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
85 | code{background-color:#fee9cc;color:rgba(0, 0, 0, 0.75);padding:1px 3px;}
86 | pre{background-color:#f5f5f5;display:block;padding:8.5px;margin:0 0 18px;line-height:18px;font-size:12px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;white-space:pre;white-space:pre-wrap;word-wrap:break-word;}
87 | form{margin-bottom:18px;}
88 | fieldset{margin-bottom:18px;padding-top:18px;}fieldset legend{display:block;padding-left:150px;font-size:19.5px;line-height:1;color:#404040;*padding:0 0 5px 145px;*line-height:1.5;}
89 | form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;}
90 | form .clearfix:after{clear:both;}
91 | label,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;}
92 | label{padding-top:6px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;}
93 | form .input{margin-left:150px;}
94 | input[type=checkbox],input[type=radio]{cursor:pointer;}
95 | input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
96 | select{padding:initial;}
97 | input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;}
98 | input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
99 | input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;}
100 | select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;}
101 | select[multiple]{height:inherit;background-color:#ffffff;}
102 | textarea{height:auto;}
103 | .uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
104 | :-moz-placeholder{color:#bfbfbf;}
105 | ::-webkit-input-placeholder{color:#bfbfbf;}
106 | input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);}
107 | input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);}
108 | input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;}
109 | form .clearfix.error>label,form .clearfix.error .help-block,form .clearfix.error .help-inline{color:#b94a48;}
110 | form .clearfix.error input,form .clearfix.error textarea{color:#b94a48;border-color:#ee5f5b;}form .clearfix.error input:focus,form .clearfix.error textarea:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
111 | form .clearfix.error .input-prepend .add-on,form .clearfix.error .input-append .add-on{color:#b94a48;background-color:#fce6e6;border-color:#b94a48;}
112 | form .clearfix.warning>label,form .clearfix.warning .help-block,form .clearfix.warning .help-inline{color:#c09853;}
113 | form .clearfix.warning input,form .clearfix.warning textarea{color:#c09853;border-color:#ccae64;}form .clearfix.warning input:focus,form .clearfix.warning textarea:focus{border-color:#be9a3f;-webkit-box-shadow:0 0 6px #e5d6b1;-moz-box-shadow:0 0 6px #e5d6b1;box-shadow:0 0 6px #e5d6b1;}
114 | form .clearfix.warning .input-prepend .add-on,form .clearfix.warning .input-append .add-on{color:#c09853;background-color:#d2b877;border-color:#c09853;}
115 | form .clearfix.success>label,form .clearfix.success .help-block,form .clearfix.success .help-inline{color:#468847;}
116 | form .clearfix.success input,form .clearfix.success textarea{color:#468847;border-color:#57a957;}form .clearfix.success input:focus,form .clearfix.success textarea:focus{border-color:#458845;-webkit-box-shadow:0 0 6px #9acc9a;-moz-box-shadow:0 0 6px #9acc9a;box-shadow:0 0 6px #9acc9a;}
117 | form .clearfix.success .input-prepend .add-on,form .clearfix.success .input-append .add-on{color:#468847;background-color:#bcddbc;border-color:#468847;}
118 | .input-mini,input.mini,textarea.mini,select.mini{width:60px;}
119 | .input-small,input.small,textarea.small,select.small{width:90px;}
120 | .input-medium,input.medium,textarea.medium,select.medium{width:150px;}
121 | .input-large,input.large,textarea.large,select.large{width:210px;}
122 | .input-xlarge,input.xlarge,textarea.xlarge,select.xlarge{width:270px;}
123 | .input-xxlarge,input.xxlarge,textarea.xxlarge,select.xxlarge{width:530px;}
124 | textarea.xxlarge{overflow-y:auto;}
125 | input.span1,textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;}
126 | input.span2,textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;}
127 | input.span3,textarea.span3{display:inline-block;float:none;width:150px;margin-left:0;}
128 | input.span4,textarea.span4{display:inline-block;float:none;width:210px;margin-left:0;}
129 | input.span5,textarea.span5{display:inline-block;float:none;width:270px;margin-left:0;}
130 | input.span6,textarea.span6{display:inline-block;float:none;width:330px;margin-left:0;}
131 | input.span7,textarea.span7{display:inline-block;float:none;width:390px;margin-left:0;}
132 | input.span8,textarea.span8{display:inline-block;float:none;width:450px;margin-left:0;}
133 | input.span9,textarea.span9{display:inline-block;float:none;width:510px;margin-left:0;}
134 | input.span10,textarea.span10{display:inline-block;float:none;width:570px;margin-left:0;}
135 | input.span11,textarea.span11{display:inline-block;float:none;width:630px;margin-left:0;}
136 | input.span12,textarea.span12{display:inline-block;float:none;width:690px;margin-left:0;}
137 | input.span13,textarea.span13{display:inline-block;float:none;width:750px;margin-left:0;}
138 | input.span14,textarea.span14{display:inline-block;float:none;width:810px;margin-left:0;}
139 | input.span15,textarea.span15{display:inline-block;float:none;width:870px;margin-left:0;}
140 | input.span16,textarea.span16{display:inline-block;float:none;width:930px;margin-left:0;}
141 | input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
142 | .actions{background:#f5f5f5;margin-top:18px;margin-bottom:18px;padding:17px 20px 18px 150px;border-top:1px solid #ddd;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.actions .secondary-action{float:right;}.actions .secondary-action a{line-height:30px;}.actions .secondary-action a:hover{text-decoration:underline;}
143 | .help-inline,.help-block{font-size:13px;line-height:18px;color:#bfbfbf;}
144 | .help-inline{padding-left:5px;*position:relative;*top:-5px;}
145 | .help-block{display:block;max-width:600px;}
146 | .inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;}
147 | .input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
148 | .input-prepend .add-on,.input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
149 | .input-prepend .active,.input-append .active{background:#a9dba9;border-color:#46a546;}
150 | .input-prepend .add-on{*margin-top:1px;}
151 | .input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
152 | .input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;}
153 | .inputs-list{margin:0 0 5px;width:100%;}.inputs-list li{display:block;padding:0;width:100%;}
154 | .inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}.inputs-list label strong{color:#808080;}
155 | .inputs-list label small{font-size:11px;font-weight:normal;}
156 | .inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;}
157 | .inputs-list:first-child{padding-top:6px;}
158 | .inputs-list li+li{padding-top:2px;}
159 | .inputs-list input[type=radio],.inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;}
160 | .form-stacked{padding-left:20px;}.form-stacked fieldset{padding-top:9px;}
161 | .form-stacked legend{padding-left:0;}
162 | .form-stacked label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;}
163 | .form-stacked .clearfix{margin-bottom:9px;}.form-stacked .clearfix div.input{margin-left:0;}
164 | .form-stacked .inputs-list{margin-bottom:0;}.form-stacked .inputs-list li{padding-top:0;}.form-stacked .inputs-list li label{font-weight:normal;padding-top:0;}
165 | .form-stacked div.clearfix.error{padding-top:10px;padding-bottom:10px;padding-left:10px;margin-top:0;margin-left:-10px;}
166 | .form-stacked .actions{margin-left:-20px;padding-left:20px;}
167 | table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}table th,table td{padding:10px 10px 9px;line-height:18px;text-align:left;}
168 | table th{padding-top:9px;font-weight:bold;vertical-align:middle;}
169 | table td{vertical-align:top;border-top:1px solid #ddd;}
170 | table tbody th{border-top:1px solid #ddd;vertical-align:top;}
171 | .condensed-table th,.condensed-table td{padding:5px 5px 4px;}
172 | .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;}
173 | .bordered-table thead tr:first-child th:first-child,.bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
174 | .bordered-table thead tr:first-child th:last-child,.bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
175 | .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
176 | .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
177 | .zebra-striped tbody tr:nth-child(odd) td,.zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
178 | .zebra-striped tbody tr:hover td,.zebra-striped tbody tr:hover th{background-color:#f5f5f5;}
179 | table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;}
180 | table .headerSortUp,table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);}
181 | table .header:hover:after{visibility:visible;}
182 | table .headerSortDown:after,table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
183 | table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
184 | table .blue{color:#049cdb;border-bottom-color:#049cdb;}
185 | table .headerSortUp.blue,table .headerSortDown.blue{background-color:#ade6fe;}
186 | table .green{color:#46a546;border-bottom-color:#46a546;}
187 | table .headerSortUp.green,table .headerSortDown.green{background-color:#cdeacd;}
188 | table .red{color:#9d261d;border-bottom-color:#9d261d;}
189 | table .headerSortUp.red,table .headerSortDown.red{background-color:#f4c8c5;}
190 | table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;}
191 | table .headerSortUp.yellow,table .headerSortDown.yellow{background-color:#fff6d9;}
192 | table .orange{color:#f89406;border-bottom-color:#f89406;}
193 | table .headerSortUp.orange,table .headerSortDown.orange{background-color:#fee9cc;}
194 | table .purple{color:#7a43b6;border-bottom-color:#7a43b6;}
195 | table .headerSortUp.purple,table .headerSortDown.purple{background-color:#e2d5f0;}
196 | .pills a{margin:5px 3px 5px 0;padding:0 15px;line-height:30px;text-shadow:0 1px 1px #ffffff;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}.pills a:hover{color:#ffffff;text-decoration:none;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#00438a;}
197 | .pills .active a{color:#ffffff;text-shadow:0 1px 1px rgba(0, 0, 0, 0.25);background-color:#0069d6;}
198 | .pills-vertical>li{float:none;}
199 | .tab-content>.tab-pane,.pill-content>.pill-pane,.tab-content>div,.pill-content>div{display:none;}
200 | .tab-content>.active,.pill-content>.active{display:block;}
201 | .hero-unit{background-color:#f5f5f5;margin-bottom:30px;padding:60px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;}
202 | .hero-unit p{font-size:18px;font-weight:200;line-height:27px;}
203 | footer{margin-top:17px;padding-top:17px;border-top:1px solid #eee;}
204 | .page-header{margin-bottom:17px;border-bottom:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;}
205 | .btn.danger,.alert-message.danger,.btn.danger:hover,.alert-message.danger:hover,.btn.error,.alert-message.error,.btn.error:hover,.alert-message.error:hover,.btn.success,.alert-message.success,.btn.success:hover,.alert-message.success:hover,.btn.info,.alert-message.info,.btn.info:hover,.alert-message.info:hover{color:#ffffff;}
206 | .btn .close,.alert-message .close{font-family:Arial,sans-serif;line-height:18px;}
207 | .btn.danger,.alert-message.danger,.btn.error,.alert-message.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
208 | .btn.success,.alert-message.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
209 | .btn.info,.alert-message.info{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
210 | .btn{cursor:pointer;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);padding:5px 14px 6px;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);color:#333;font-size:13px;line-height:normal;border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;-ms-transition:0.1s linear all;-o-transition:0.1s linear all;transition:0.1s linear all;}.btn:hover{background-position:0 -15px;color:#333;text-decoration:none;}
211 | .btn:focus{outline:1px dotted #666;}
212 | .btn.primary{color:#ffffff;background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(top, #049cdb, #0064cd);background-image:-ms-linear-gradient(top, #049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(top, #049cdb, #0064cd);background-image:-o-linear-gradient(top, #049cdb, #0064cd);background-image:linear-gradient(top, #049cdb, #0064cd);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);border-color:#0064cd #0064cd #003f81;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
213 | .btn.active,.btn:active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.25),0 1px 2px rgba(0, 0, 0, 0.05);}
214 | .btn.disabled{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
215 | .btn[disabled]{cursor:default;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
216 | .btn.large{font-size:15px;line-height:normal;padding:9px 14px 9px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
217 | .btn.small{padding:7px 9px 7px;font-size:11px;}
218 | :root .alert-message,:root .btn{border-radius:0 \0;}
219 | button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0;}
220 | .close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=25);-khtml-opacity:0.25;-moz-opacity:0.25;opacity:0.25;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;}
221 | .pagination{height:36px;margin:18px 0;}.pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
222 | .pagination li{display:inline;}
223 | .pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;}
224 | .pagination a:hover,.pagination .active a{background-color:#c7eefe;}
225 | .pagination .disabled a,.pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;}
226 | .pagination .next a{border:0;}
227 | .well{background-color:#f5f5f5;margin-bottom:20px;padding:19px;min-height:20px;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
228 | .modal-backdrop{background-color:#000000;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;}.modal-backdrop.fade{opacity:0;}
229 | .modal-backdrop,.modal-backdrop.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}
230 | .modal{position:fixed;top:50%;left:50%;z-index:11000;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal .close{margin-top:7px;}
231 | .modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
232 | .modal.fade.in{top:50%;}
233 | .modal-header{border-bottom:1px solid #eee;padding:5px 15px;}
234 | .modal-body{padding:15px;}
235 | .modal-body form{margin-bottom:0;}
236 | .modal-footer{background-color:#f5f5f5;padding:14px 15px 15px;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;zoom:1;margin-bottom:0;}.modal-footer:before,.modal-footer:after{display:table;content:"";zoom:1;}
237 | .modal-footer:after{clear:both;}
238 | .modal-footer .btn{float:right;margin-left:5px;}
239 | .modal .popover,.modal .twipsy{z-index:12000;}
240 | .twipsy{display:block;position:absolute;visibility:visible;padding:5px;font-size:11px;z-index:1000;filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}.twipsy.fade.in{filter:alpha(opacity=80);-khtml-opacity:0.8;-moz-opacity:0.8;opacity:0.8;}
241 | .twipsy.above .twipsy-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
242 | .twipsy.left .twipsy-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
243 | .twipsy.below .twipsy-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
244 | .twipsy.right .twipsy-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
245 | .twipsy-inner{padding:3px 8px;background-color:#000000;color:white;text-align:center;max-width:200px;text-decoration:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
246 | .twipsy-arrow{position:absolute;width:0;height:0;}
247 | .fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
248 | .label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;white-space:nowrap;background-color:#bfbfbf;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}.label.important{background-color:#c43c35;}
249 | .label.warning{background-color:#f89406;}
250 | .label.success{background-color:#46a546;}
251 | .label.notice{background-color:#62cffc;}
--------------------------------------------------------------------------------
/static/prettify.css:
--------------------------------------------------------------------------------
1 | .com { color: #93a1a1; }
2 | .lit { color: #195f91; }
3 | .pun, .opn, .clo { color: #93a1a1; }
4 | .fun { color: #dc322f; }
5 | .str, .atv { color: #268bd2; }
6 | .kwd, .tag { color: #195f91; }
7 | .typ, .atn, .dec, .var { color: #CB4B16; }
8 | .pln { color: #93a1a1; }
9 | .prettyprint {
10 | background-color: #fefbf3;
11 | padding: 9px;
12 | border: 1px solid rgba(0,0,0,.2);
13 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1);
14 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1);
15 | box-shadow: 0 1px 2px rgba(0,0,0,.1);
16 | }
17 |
18 | /* Specify class=linenums on a pre to get line numbering */
19 | ol.linenums {
20 | margin: 0 0 0 40px;
21 | }
22 | /* IE indents via margin-left */
23 | ol.linenums li {
24 | padding: 0 5px;
25 | color: rgba(0,0,0,.15);
26 | line-height: 20px;
27 | -webkit-border-radius: 2px;
28 | -moz-border-radius: 2px;
29 | border-radius: 2px;
30 | }
31 | /* Alternate shading for lines */
32 | li.L1, li.L3, li.L5, li.L7, li.L9 { }
33 |
34 | /*
35 | $base03: #002b36;
36 | $base02: #073642;
37 | $base01: #586e75;
38 | $base00: #657b83;
39 | $base0: #839496;
40 | $base1: #93a1a1;
41 | $base2: #eee8d5;
42 | $base3: #fdf6e3;
43 | $yellow: #b58900;
44 | $orange: #cb4b16;
45 | $red: #dc322f;
46 | $magenta: #d33682;
47 | $violet: #6c71c4;
48 | $blue: #268bd2;
49 | $cyan: #2aa198;
50 | $green: #859900;
51 | */
52 |
53 |
54 | /*
55 | #1d1f21 Background
56 | #282a2e Current Line
57 | #373b41 Selection
58 | #c5c8c6 Foreground
59 | #969896 Comment
60 | #cc6666 Red
61 | #de935f Orange
62 | #f0c674 Yellow
63 | #b5bd68 Green
64 | #8abeb7 Aqua
65 | #81a2be Blue
66 | #b294bb Purple
67 | */
68 |
69 |
70 | /* DARK THEME */
71 | /* ---------- */
72 |
73 | .prettyprint-dark {
74 | background-color: #1d1f21;
75 | border: 0;
76 | padding: 10px;
77 | }
78 | .prettyprint-dark .linenums li {
79 | color: #444;
80 | }
81 | .prettyprint-dark .linenums li:hover {
82 | background-color: #282a2e;
83 | }
84 | /* tags in html */
85 | .prettyprint-dark .kwd,
86 | .prettyprint-dark .tag { color: #cc6666; }
87 | /* html attr */
88 | .prettyprint-dark .typ,
89 | .prettyprint-dark .atn,
90 | .prettyprint-dark .dec,
91 | .prettyprint-dark .var { color: #de935f; }
92 | /* html attr values */
93 | .prettyprint-dark .str,
94 | .prettyprint-dark .atv { color: #b5bd68; }
95 |
--------------------------------------------------------------------------------
/static/prettify.js:
--------------------------------------------------------------------------------
1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^
60 |
80 | {% end %}
81 |
82 |
--------------------------------------------------------------------------------
/templates/entry.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}{{ entry.title }}——{{ escape(handler.settings["sitename"]) }}{% end %}
3 | {% block head %}
4 |
5 |
6 | {% end %}
7 |
8 | {% block body %}
9 |
10 |
11 |
14 |
15 | DElete
16 |
17 |
18 | Update
19 |
20 |
21 |
22 |
Code info
23 |
24 | {{ entry.info }}
25 | {{ entry.published.strftime('%Y-%m-%d %H:%M') }}
26 |
27 | {% if current_user %}
28 |
29 | {% end %}
30 |
31 |
32 |
33 |
34 |
38 |
51 | {{ xsrf_form_html() }}
52 |
55 |
56 |
57 |
58 |
59 |
63 |
76 | {{ xsrf_form_html() }}
77 |
80 |
81 |
82 |
83 | {% end %}
84 | {% block bottom %}
85 |
86 |
87 |
88 |
89 | {% end %}
--------------------------------------------------------------------------------
/templates/feed.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | {{ escape(handler.settings["sitename"]) }}
5 |
6 | http://{{ request.host }}/
7 | A simple code share site runing SAE.
8 | {% set date_format = "%Y-%m-%dT%H:%M:%SZ" %}
9 | {% if len(entries) > 0 %}
10 | {{ max(e.updated for e in entries).strftime(date_format) }}
11 | {% else %}
12 | {{ datetime.datetime.utcnow().strftime(date_format) }}
13 | {% end %}
14 | cn
15 | hourly
16 | 1
17 | http://wordpress.org/?v=3.2.1
18 | {{ escape(handler.settings["sitename"]) }}
19 | {% for entry in entries %}
20 | -
21 | {{ escape(entry.title) }}
22 | http://{{ request.host }}/{{ entry.slug }}
23 | {{ entry.published.strftime(date_format) }}
24 |
25 |
26 |
27 |
28 |
29 | {% end %}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/templates/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block body %}
4 |
5 |
6 |
7 | 序号 |
8 | 标题 |
9 | 介绍 |
10 |
11 |
12 |
13 | {% for i,entry in enumerate(entries) %}
14 |
15 | #{{counts-i}} |
16 | {{entry.title}} |
17 | {{entry.info[ :100]}} |
18 |
19 | {% end %}
20 |
21 |
22 |
57 | {% end %}
58 |
--------------------------------------------------------------------------------
/templates/login.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}管理员登录{% end %}
3 | {% block body %}
4 |
28 | {% end %}
29 |
30 | {% block bottom %}
31 |
32 |
33 |
53 | {% end %}
54 |
55 |
--------------------------------------------------------------------------------
/templates/page.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}第{{ this }}页——{{ escape(handler.settings["sitename"]) }}{% end %}
3 | {% block body %}
4 |
5 |
6 |
7 |
8 | 序号 |
9 | 标题 |
10 | 介绍 |
11 |
12 |
13 |
14 | {% for i,entry in enumerate(entries) %}
15 |
16 | #{{counts-(this-1)*8-i}} |
17 | {{entry.title}} |
18 | {{entry.info[ :100]}} |
19 |
20 | {% end %}
21 |
22 |
23 |
24 |
93 | {% end %}
94 |
--------------------------------------------------------------------------------
/templates/start.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}基本设置——准备开始{% end %}
3 | {% block body %}
4 |
34 | {% end %}
35 |
36 | {% block bottom %}
37 |
38 |
39 |
59 | {% end %}
60 |
61 |
--------------------------------------------------------------------------------
/templates/update.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}修改代码——Code Share{% end %}
3 | {% block body %}
4 |
46 | {% end %}
47 |
48 | {% block bottom %}
49 |
50 |
51 |
71 | {% end %}
72 |
--------------------------------------------------------------------------------
/urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from apps import code, admin
5 |
6 | urls = [(r"/", code.HomeHandler),
7 | (r"/(\d+)", code.EntryHandler),
8 | (r"/newcode", code.ComposeHandler),
9 | (r"/user/login", code.UserLoginHandler),
10 | (r"/update/(\d+)", code.UpdateHandler),
11 | (r"/delete", code.DeleteHandler),
12 | (r"/page/(\d+)", code.PageHandler),
13 | (r"/auth/login", admin.LoginHandler),
14 | (r"/auth/logout", admin.LogoutHandler),
15 | (r"/admin/start", admin.SiteStartHandler),
16 | (r"/admin/delete/(\d+)", admin.DeleteHandler),
17 | (r"/feed", code.FeedHandler), ]
18 |
--------------------------------------------------------------------------------