From 170d827e642de4980049c2ea71ebcf1852e29c9c Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Thu, 23 Feb 2012 16:44:57 +0100 Subject: Input/Read test succeed! --- failing_test.py | 49 + pyyaml/YAMLish.html | 353 ++++++ pyyaml/YAMLish_files/commonPrint.css | 290 +++++ pyyaml/YAMLish_files/gnu-fdl.png | Bin 0 -> 1748 bytes pyyaml/YAMLish_files/handheld.css | 1337 ++++++++++++++++++++ pyyaml/YAMLish_files/index.js | 9 + pyyaml/YAMLish_files/poweredby_mediawiki_88x31.png | Bin 0 -> 1933 bytes pyyaml/YAMLish_files/wikibits.js | 1246 ++++++++++++++++++ test-perl.pl | 67 + test/__init__.py | 81 +- test/all_tests.py | 16 +- test/test_input.py | 157 +-- test/test_load.py | 8 +- test/test_output.py | 10 +- test/test_reader.py | 212 ++-- test/test_writer.py | 40 +- yamlish.py | 262 ++-- 17 files changed, 3755 insertions(+), 382 deletions(-) create mode 100644 failing_test.py create mode 100644 pyyaml/YAMLish.html create mode 100644 pyyaml/YAMLish_files/commonPrint.css create mode 100644 pyyaml/YAMLish_files/gnu-fdl.png create mode 100644 pyyaml/YAMLish_files/handheld.css create mode 100644 pyyaml/YAMLish_files/index.js create mode 100644 pyyaml/YAMLish_files/poweredby_mediawiki_88x31.png create mode 100644 pyyaml/YAMLish_files/wikibits.js create mode 100644 test-perl.pl diff --git a/failing_test.py b/failing_test.py new file mode 100644 index 0000000..3a4e88c --- /dev/null +++ b/failing_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +import yaml + +IN = { + "name": 'Hello World 6', + "in": [ + "---", + "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", + "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", + "- \" !\\\"#\$%&'()*+,-./\"", + "- 0123456789:;<=>?", + "- '\@ABCDEFGHIJKLMNO'", + "- 'PQRSTUVWXYZ[\\]^_'", + "- '`abcdefghijklmno'", + "- 'pqrstuvwxyz{|}~\177'", + "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + "..."], + "out": [ + "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", + "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", + " !\"#\$%&'()*+,-./", + "0123456789:;<=>?", + "\@ABCDEFGHIJKLMNO", + "PQRSTUVWXYZ[\\]^_", + "`abcdefghijklmno", + "pqrstuvwxyz{|}~\177", + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" + ] + } + +instr = "\n".join(IN['in']) +print "type instr = %s" % type(instr) +print instr +res = yaml.load(instr, Loader=yaml.SafeLoader) +print "'%s'" % (res == IN['out']) diff --git a/pyyaml/YAMLish.html b/pyyaml/YAMLish.html new file mode 100644 index 0000000..bebe084 --- /dev/null +++ b/pyyaml/YAMLish.html @@ -0,0 +1,353 @@ + + + + + + + + + YAMLish - Test Anything Protocol + + + + + + + + + + + + + + + + + +
+
+
+ +

YAMLish

+
+

From Test Anything Protocol

+
+
Jump to: navigation, search
+

YAMLish is a small subset of YAML that TAP producers may use to embed machine readable information in TAP diagnostics. See TAP diagnostic syntax for information about how YAMLish embeds in TAP. +

+

Contents

+ +
+

[edit] Objectives

+

The main objectives for YAMLish are +

+
  • small - the Perl reader is around 124 lines, 258 lines for the parser +
  • portable - it should be reasonably easy to implement YAMLish in any language +
  • able to encode arbitrary data structures +
  • verifiable - it should be relatively to easy to test that a YAMLish implementation conforms +
  • JSON compatible - YAMLish should be a super-set of JSON to +allow TAP producers to make use of JSON libraries (objective not met) +
+

[edit] Syntax

+

To avoid the burden of distributing a complete YAML parser with a TAP + producer or consumer YAMLish confines itself to a subset of YAML +syntax. +

These examples demonstrates the supported syntax. +

All YAMLish documents must begin with '---' and end with a line containing '...'. +

+
   --- Simple scalar
+   ...
+
+

Unprintable characters are represented using standard escapes in double quoted strings. +

+
   --- "\t\x01\x02\n"
+   ...
+
+

Array and hashes are represented thusly +

+
   ---
+     - "This"
+     - "is"
+     - "an"
+     - "array"
+   ...
+
+
   ---
+     This: is
+     a: hash
+   ...
+
+

Hash keys may be double quoted strings and may contain unprintable characters +

+
   ---
+     "\t\x00": "My key is <tab><nul>"
+     "Now is the time": "t'was ever thus"
+   ...
+   
+
+

Structures may nest arbitrarily +

+
   ---
+     -
+       name: 'Hash one'
+       value: 1
+     -
+       name: 'Hash two'
+       value: 2
+   ...
+
+

Undef is a tilde +

+
   --- ~
+   ...
+
+

[edit] Root Namespace

+

When used with TAP the root element of an embedded YAMLish diagnostic is a hash containing keys from this set: +

+
message +
A textual message giving more detail about the failure (or success) +
severity +
The severity of the problem. +
source +
A uri describing the source of the TAP. This can be a file URL. See "file" for a special case. +
datetime +
the time the test was executed, helping test runners do +interesting things like run tests in order of most-recently-failed. +ISO8601 or HTTP date format. +
file +
A filename representing the TAP source, really a special case +of "source". Not possible for all TAP sources, but I really don't want +everyone to have to use file URIs. +
line +
The line number of the TAP source from which this test was produced. Not possible for all TAP sources. +
name +
Name of this test, if any. +
extensions +
A place to put any non-standard keys without worrying out conflicting with future ones +
actual +
For comparison tests, what you got. +
expected +
For comparison tests, what you expected. +
display +
Suggested text to display representing this failure +
dump +
A hash of variables to be pretty-printed by the harness +
error +
An error or exception object +
backtrace +
A stack backtrace in the case of an error or exception +
+

(please feel free to add to this list - it's provisional at the moment) +

+

[edit] Implementations

+

Because YAMLish is a subset of YAML there are already a number of +parsers in a number of languages that accept it. It's also quite likely +that existing YAML producers can be coerced into producing YAMLish +compliant YAML. Please be careful though to ensure that your YAMLish +producer does in fact conform to the subset defined here. Just because +your YAML happens to work with a particular test harness doesn't mean +that it's valid YAMLish. +

YAMLish is based on the subset of YAML supported by Adam Kennedy's YAML::Tiny + Perl module. YAML::Tiny doesn't support quoted hash keys - which we +need so that we can safely round-trip arbitrary data structures - so +YAMLish extends Adam's de-facto subset to include these. +

If your concern is only to produce well formed TAP (rather than +parsing it) then you should find that it's possible to implement a +YAMLish writer in a couple of hundred lines of code. +

+

[edit] Perl

+
  • TAP::Parser + implements YAMLish support. You'll need the version from the subversion + repository though; YAMLish support hasn't yet made it to CPAN. +
  • Data::YAML is essentially the YAMLish engine from TAP::Parser packaged as a standalone module +
+

[edit] PHP

+
  • YAMLishWriter is a simple PHP implementation of a YAMLish encoder +
+

If you have a YAMLish implementation please list it here. +

+

[edit] Q&A

+

[edit] Why YAML?

+

TAP diagnostics require a way to represent data structions in any +language in a human and machine readable form. It would be nice if we +didn't have to write our own format. YAML, like TAP, is designed to be +both human and machine readable as well as language independent. YAML portable generators and parsers already exist in many languages. portable generators YAML has already solved the hard problems facing a data serialization format (like character sets). +

+

[edit] Why not JSON?

+

JSON was considered, and it has some of the characteristics of YAML, but it was ultimately rejected for several reasons. +

JSON is, effectively, a subset of YAML. If your producer emits JSON then a YAML parser will read it. The inverse is not true. +

JSON is more verbose, less human readable, requiring more quoting. For example: +

+
 # YAML
+ ---
+ got:      this
+ expected: that
+ ...
+ 
+ # JSON
+ {
+   "got":      "this"
+   "expected": "that"
+ }
+
+

JSON lacks a WYSIWYG multi-line scalar value format. YAML has +several. | allows the exact text to be presented, newlines and all. +> "soft wraps" text to prevent long lines from spilling across the +screen. +

+
 # YAML
+ ---
+ got: >
+    When in the course of human events,
+    blah blah blah
+ expected: >
+    When, in the course of human events,
+    it becomes necessary for one people to
+    dissolve the political bonds which have 
+    connected them with another...
+ ...
+
+
 # JSON
+ {
+   "got":      "When in the course of human events, blah blah blah"
+   "expected": "When, in the course of human events, it becomes necessary for one people to dissolve the political bonds which have connected them with another..."
+ }
+
+

[edit] Why the --- and ... markers?

+

With the diagnostics indented to indicate they're diagnostics, why +the --- and ... markers? TAP producers tend to spit a lot of junk to +STDOUT, either explicitly as poorly written comments or accidentally +because the thing they're testing prints to STDOUT. We don't want just +any old indented text to be parsed, so we put the --- and ... markers +around it. The --- is there to indicate the start of a block. The ... +is there to indicate it has ended so the parser does not have to wait +for the next test line (which could take a while) to know there's no +more diagnostics for the previous test forthcoming. +

+ + + +
+
+
+
+
+
+
Views
+
+ +
+
+
+
Personal tools
+ +
+ + + + + +
+
+ + + + +
+ + \ No newline at end of file diff --git a/pyyaml/YAMLish_files/commonPrint.css b/pyyaml/YAMLish_files/commonPrint.css new file mode 100644 index 0000000..4fddafa --- /dev/null +++ b/pyyaml/YAMLish_files/commonPrint.css @@ -0,0 +1,290 @@ +/* +** MediaWiki Print style sheet for CSS2-capable browsers. +** Copyright Gabriel Wicke, http://www.aulinx.de/ +** +** Derived from the plone (http://plone.org/) styles +** Copyright Alexander Limi +*/ + +/* Thanks to A List Apart (http://alistapart.com/) for useful extras */ +a.stub, +a.new{ color:#ba0000; text-decoration:none; } + +#toc { + /*border:1px solid #2f6fab;*/ + border:1px solid #aaaaaa; + background-color:#f9f9f9; + padding:5px; +} +.tocindent { + margin-left: 2em; +} +.tocline { + margin-bottom: 0px; +} + +/* images */ +div.floatright { + float: right; + clear: right; + margin: 0; + position:relative; + border: 0.5em solid White; + border-width: 0.5em 0 0.8em 1.4em; +} +div.floatright p { font-style: italic;} +div.floatleft { + float: left; + margin: 0.3em 0.5em 0.5em 0; + position:relative; + border: 0.5em solid White; + border-width: 0.5em 1.4em 0.8em 0; +} +div.floatleft p { font-style: italic; } +/* thumbnails */ +div.thumb { + margin-bottom: 0.5em; + border-style: solid; border-color: White; + width: auto; + overflow: hidden; +} +div.thumb div { + border:1px solid #cccccc; + padding: 3px !important; + background-color:#f9f9f9; + font-size: 94%; + text-align: center; +} +div.thumb div a img { + border:1px solid #cccccc; +} +div.thumb div div.thumbcaption { + border: none; + padding: 0.3em 0 0.1em 0; +} +div.magnify { display: none; } +div.tright { + float: right; + clear: right; + border-width: 0.5em 0 0.8em 1.4em; +} +div.tleft { + float: left; + margin-right:0.5em; + border-width: 0.5em 1.4em 0.8em 0; +} + +/* table standards */ +table.rimage { + float:right; + width:1pt; + position:relative; + margin-left:1em; + margin-bottom:1em; + text-align:center; +} + +body { + background: White; + /*font-size: 11pt !important;*/ + color: Black; + margin: 0; + padding: 0; +} + +.noprint, +div#jump-to-nav, +div.top, +div#column-one, +#colophon, +.editsection, +.toctoggle, +.tochidden, +div#f-poweredbyico, +div#f-copyrightico, +li#viewcount, +li#about, +li#disclaimer, +li#privacy { + /* Hides all the elements irrelevant for printing */ + display: none; +} + +ul { + list-style-type: square; +} + +#content { + background: none; + border: none ! important; + padding: 0 ! important; + margin: 0 ! important; +} +#footer { + background : white; + color : black; + border-top: 1px solid black; +} + +h1, h2, h3, h4, h5, h6 +{ + font-weight: bold; +} + +p, .documentDescription { + margin: 1em 0 ! important; + line-height: 1.2em; +} + +.tocindent p { + margin: 0 0 0 0 ! important; +} + +pre { + border: 1pt dashed black; + white-space: pre; + font-size: 8pt; + overflow: auto; + padding: 1em 0; + background : white; + color : black; +} + +table.listing, +table.listing td { + border: 1pt solid black; + border-collapse: collapse; +} + +a { + color: Black !important; + background: none !important; + padding: 0 !important; +} + +a:link, a:visited { + color: #520; + background: transparent; + text-decoration: underline; +} + +#content a.external.text:after, #content a.external.autonumber:after { + /* Expand URLs for printing */ + content: " (" attr(href) ") "; +} + +#globalWrapper { + width: 100% !important; + min-width: 0 !important; +} + +#content { + background : white; + color : black; +} + +#column-content { + margin: 0 !important; +} + +#column-content #content { + padding: 1em; + margin: 0 !important; +} +/* MSIE/Win doesn't understand 'inherit' */ +a, a.external, a.new, a.stub { + color: black ! important; + text-decoration: none ! important; +} + +/* Continue ... */ +a, a.external, a.new, a.stub { + color: inherit ! important; + text-decoration: inherit ! important; +} + +img { border: none; } +img.tex { vertical-align: middle; } +span.texhtml { font-family: serif; } + +div.townBox { + position:relative; + float:right; + background:White; + margin-left:1em; + border: 1px solid gray; + padding:0.3em; + width: 200px; + overflow: hidden; + clear: right; +} +div.townBox dl { + padding: 0; + margin: 0 0 0.3em 0; + font-size: 96%; +} +div.townBox dl dt { + background: none; + margin: 0.4em 0 0 0; +} +div.townBox dl dd { + margin: 0.1em 0 0 1.1em; + background-color: #f3f3f3; +} + +#siteNotice { display: none; } + +table.gallery { + border: 1px solid #cccccc; + margin: 2px; + padding: 2px; + background-color:#ffffff; +} + +table.gallery tr { + vertical-align:top; +} + +div.gallerybox { + border: 1px solid #cccccc; + margin: 2px; + background-color:#f9f9f9; + width: 150px; +} + +div.gallerybox div.thumb { + text-align: center; + border: 1px solid #cccccc; + margin: 2px; +} + +div.gallerytext { + font-size: 94%; + padding: 2px 4px; +} + +/* +** Diff rendering +*/ +table.diff { background:white; } +td.diff-otitle { background:#ffffff; } +td.diff-ntitle { background:#ffffff; } +td.diff-addedline { + background:#ccffcc; + font-size: smaller; + border: solid 2px black; +} +td.diff-deletedline { + background:#ffffaa; + font-size: smaller; + border: dotted 2px black; +} +td.diff-context { + background:#eeeeee; + font-size: smaller; +} +.diffchange { + color: silver; + font-weight: bold; + text-decoration: underline; +} diff --git a/pyyaml/YAMLish_files/gnu-fdl.png b/pyyaml/YAMLish_files/gnu-fdl.png new file mode 100644 index 0000000..1371aba Binary files /dev/null and b/pyyaml/YAMLish_files/gnu-fdl.png differ diff --git a/pyyaml/YAMLish_files/handheld.css b/pyyaml/YAMLish_files/handheld.css new file mode 100644 index 0000000..754aba9 --- /dev/null +++ b/pyyaml/YAMLish_files/handheld.css @@ -0,0 +1,1337 @@ +/* +** MediaWiki 'monobook' style sheet for CSS2-capable browsers. +** Copyright Gabriel Wicke - http://wikidev.net/ +** License: GPL (http://www.gnu.org/copyleft/gpl.html) +** +** Loosely based on http://www.positioniseverything.net/ordered-floats.html by Big John +** and the Plone 2.0 styles, see http://plone.org/ (Alexander Limi,Joe Geldart & Tom Croucher, +** Michael Zeltner and Geir Bækholt) +** All you guys rock :) +*/ + +/** + * Stylesheet for handhelds. All rules not marked media-specific are shared + * with main.css and should be updated in tandem. The rules can't be in the + * same file because old browsers like IE5 won't obey @media rules. + * + * Rules that are handheld-specific are given @media rules in case old browsers + * don't recognize the media attribute and load this file anyway. + */ + +#content { + background: white; + color: black; + border: 1px solid #aaa; + border-right: none; + line-height: 1.5em; +} +/* the left column width is specified in class .portlet */ + +/* Font size: +** We take advantage of keyword scaling- browsers won't go below 9px +** More at http://www.w3.org/2003/07/30-font-size +** http://style.cleverchimp.com/font_size_intervals/altintervals.html +*/ + +body { + font: x-small sans-serif; + background: #f9f9f9 url(headbg.jpg) 0 0 no-repeat; + color: black; + margin: 0; + padding: 0; +} + +/* scale back up to a sane default */ +#globalWrapper { + font-size: 127%; + width: 100%; + margin: 0; + padding: 0; +} +.visualClear { + clear: both; +} + +/* general styles */ + +table { + font-size: 100%; + color: black; + /* we don't want the bottom borders of

s to be visible through + floated tables */ + background-color: white; +} +a { + text-decoration: none; + color: #002bb8; + background: none; +} +a:visited { + color: #5a3696; +} +a:active { + color: #faa700; +} +a:hover { + text-decoration: underline; +} +a.stub { + color: #772233; +} +a.new, #p-personal a.new { + color: #ba0000; +} +a.new:visited, #p-personal a.new:visited { + color: #a55858; +} + +img { + border: none; + vertical-align: middle; +} +p img { + margin: 0; +} + +hr { + height: 1px; + color: #aaa; + background-color: #aaa; + border: 0; + margin: .2em 0 .2em 0; +} + +h1, h2, h3, h4, h5, h6 { + color: black; + background: none; + font-weight: normal; + margin: 0; + padding-top: .5em; + padding-bottom: .17em; + border-bottom: 1px solid #aaa; +} +h1 { font-size: 188%; } +h1 .editsection { font-size: 53%; } +h2 { font-size: 150%; } +h2 .editsection { font-size: 67%; } +h3, h4, h5, h6 { + border-bottom: none; + font-weight: bold; +} +h3 { font-size: 132%; } +h3 .editsection { font-size: 76%; font-weight: normal; } +h4 { font-size: 116%; } +h4 .editsection { font-size: 86%; font-weight: normal; } +h5 { font-size: 100%; } +h5 .editsection { font-weight: normal; } +h6 { font-size: 80%; } +h6 .editsection { font-size: 125%; font-weight: normal; } + +.editsection { + float: right; + margin-left: 5px; +} + +ul { + line-height: 1.5em; + list-style-type: square; + margin: .3em 0 0 1.5em; + padding: 0; + list-style-image: url(bullet.gif); +} +ol { + line-height: 1.5em; + margin: .3em 0 0 3.2em; + padding: 0; + list-style-image: none; +} +li { + margin-bottom: .1em; +} +dt { + font-weight: bold; + margin-bottom: .1em; +} +dl { + margin-top: .2em; + margin-bottom: .5em; +} +dd { + line-height: 1.5em; + margin-left: 2em; + margin-bottom: .1em; +} + +fieldset { + border: 1px solid #2f6fab; + margin: 1em 0 1em 0; + padding: 0 1em 1em; + line-height: 1.5em; +} +legend { + padding: .5em; + font-size: 95%; +} +form { + border: none; + margin: 0; +} + +textarea { + width: 100%; + padding: .1em; +} + +input.historysubmit { + padding: 0 .3em .3em .3em !important; + font-size: 94%; + cursor: pointer; + height: 1.7em !important; + margin-left: 1.6em; +} +select { + vertical-align: top; +} +abbr, acronym, .explain { + border-bottom: 1px dotted black; + color: black; + background: none; + cursor: help; +} +q { + font-family: Times, "Times New Roman", serif; + font-style: italic; +} +/* disabled for now +blockquote { + font-family: Times, "Times New Roman", serif; + font-style: italic; +}*/ +code { + background-color: #f9f9f9; +} +pre { + padding: 1em; + border: 1px dashed #2f6fab; + color: black; + background-color: #f9f9f9; + line-height: 1.1em; +} + +/* +** the main content area +*/ + +#contentSub, #contentSub2 { + font-size: 84%; + line-height: 1.2em; + margin: 0 0 1.4em 1em; + color: #7d7d7d; + width: auto; +} +span.subpages { + display: block; +} + +/* Some space under the headers in the content area */ +#bodyContent h1, #bodyContent h2 { + margin-bottom: .6em; +} +#bodyContent h3, #bodyContent h4, #bodyContent h5 { + margin-bottom: .3em; +} +.firstHeading { + margin-bottom: .1em; +} + +/* user notification thing */ +.usermessage { + background-color: #ffce7b; + border: 1px solid #ffa500; + color: black; + font-weight: bold; + margin: 2em 0 1em; + padding: .5em 1em; + vertical-align: middle; +} +#siteNotice { + text-align: center; + font-size: 95%; + padding: 0 .9em; +} +#siteNotice p { + margin: 0; + padding: 0; +} +.error { + color: red; + font-size: larger; +} +.errorbox, .successbox { + font-size: larger; + border: 2px solid; + padding: .5em 1em; + float: left; + margin-bottom: 2em; + color: #000; +} +.errorbox { + border-color: red; + background-color: #fff2f2; +} +.successbox { + border-color: green; + background-color: #dfd; +} +.errorbox h2, .successbox h2 { + font-size: 1em; + font-weight: bold; + display: inline; + margin: 0 .5em 0 0; + border: none; +} + +#catlinks { + border: 1px solid #aaa; + background-color: #f9f9f9; + padding: 5px; + margin-top: 1em; + clear: both; +} +/* currently unused, intended to be used by a metadata box +in the bottom-right corner of the content area */ +.documentDescription { + /* The summary text describing the document */ + font-weight: bold; + display: block; + margin: 1em 0; + line-height: 1.5em; +} +.documentByLine { + text-align: right; + font-size: 90%; + clear: both; + font-weight: normal; + color: #76797c; +} + +/* emulate center */ +.center { + width: 100%; + text-align: center; +} +*.center * { + margin-left: auto; + margin-right: auto; +} +/* small for tables and similar */ +.small, .small * { + font-size: 94%; +} +table.small { + font-size: 100%; +} + +/* +** content styles +*/ + +#toc, +.toc, +.mw-warning { + border: 1px solid #aaa; + background-color: #f9f9f9; + padding: 5px; + font-size: 95%; +} +#toc h2, +.toc h2 { + display: inline; + border: none; + padding: 0; + font-size: 100%; + font-weight: bold; +} +#toc #toctitle, +.toc #toctitle, +#toc .toctitle, +.toc .toctitle { + text-align: center; +} +#toc ul, +.toc ul { + list-style-type: none; + list-style-image: none; + margin-left: 0; + padding-left: 0; + text-align: left; +} +#toc ul ul, +.toc ul ul { + margin: 0 0 0 2em; +} +#toc .toctoggle, +.toc .toctoggle { + font-size: 94%; +} + +.mw-warning { + margin-left: 50px; + margin-right: 50px; + text-align: center; +} + +/* images */ +div.floatright, table.floatright { + clear: right; + float: right; + position: relative; + margin: 0 0 .5em .5em; + border: 0; +/* + border: .5em solid white; + border-width: .5em 0 .8em 1.4em; +*/ +} +div.floatright p { font-style: italic; } +div.floatleft, table.floatleft { + float: left; + clear: left; + position: relative; + margin: 0 .5em .5em 0; + border: 0; +/* + margin: .3em .5em .5em 0; + border: .5em solid white; + border-width: .5em 1.4em .8em 0; +*/ +} +div.floatleft p { font-style: italic; } +/* thumbnails */ +div.thumb { + margin-bottom: .5em; + border-style: solid; + border-color: white; + width: auto; +} +div.thumbinner { + border: 1px solid #ccc; + padding: 3px !important; + background-color: #f9f9f9; + font-size: 94%; + text-align: center; + overflow: hidden; +} +html .thumbimage { + border: 1px solid #ccc; +} +html .thumbcaption { + border: none; + text-align: left; + line-height: 1.4em; + padding: 3px !important; + font-size: 94%; +} +div.magnify { + float: right; + border: none !important; + background: none !important; +} +div.magnify a, div.magnify img { + display: block; + border: none !important; + background: none !important; +} +div.tright { + clear: right; + float: right; + border-width: .5em 0 .8em 1.4em; +} +div.tleft { + float: left; + clear: left; + margin-right: .5em; + border-width: .5em 1.4em .8em 0; +} + +.hiddenStructure { + display: none; + speak: none; +} +img.tex { + vertical-align: middle; +} +span.texhtml { + font-family: serif; +} + +/* +** classes for special content elements like town boxes +** intended to be referenced directly from the wiki src +*/ + +/* +** User styles +*/ +/* table standards */ +table.rimage { + float: right; + position: relative; + margin-left: 1em; + margin-bottom: 1em; + text-align: center; +} +.toccolours { + border: 1px solid #aaa; + background-color: #f9f9f9; + padding: 5px; + font-size: 95%; +} +div.townBox { + position: relative; + float: right; + background: white; + margin-left: 1em; + border: 1px solid gray; + padding: .3em; + width: 200px; + overflow: hidden; + clear: right; +} +div.townBox dl { + padding: 0; + margin: 0 0 .3em; + font-size: 96%; +} +div.townBox dl dt { + background: none; + margin: .4em 0 0; +} +div.townBox dl dd { + margin: .1em 0 0 1.1em; + background-color: #f3f3f3; +} + +/* +** edit views etc +*/ +.special li { + line-height: 1.4em; + margin: 0; + padding: 0; +} + +/* Page history styling */ +/* the auto-generated edit comments */ +.autocomment { + color: gray; +} +#pagehistory span.user { + margin-left: 1.4em; + margin-right: .4em; +} +#pagehistory span.minor { + font-weight: bold; +} +#pagehistory li { + border: 1px solid white; +} +#pagehistory li.selected { + background-color: #f9f9f9; + border: 1px dashed #aaa; +} + +/* +** Diff rendering +*/ +table.diff, td.diff-otitle, td.diff-ntitle { + background-color: white; +} +td.diff-addedline { + background: #cfc; + font-size: smaller; +} +td.diff-deletedline { + background: #ffa; + font-size: smaller; +} +td.diff-context { + background: #eee; + font-size: smaller; +} +.diffchange { + color: red; + font-weight: bold; +} + +/* +** keep the whitespace in front of the ^=, hides rule from konqueror +** this is css3, the validator doesn't like it when validating as css2 +*/ +#bodyContent a.external, +#bodyContent a[href ^="gopher://"] { + background: url(external.png) center right no-repeat; + padding-right: 13px; +} +#bodyContent a[href ^="https://"], +.link-https { + background: url(lock_icon.gif) center right no-repeat; + padding-right: 16px; +} +#bodyContent a[href ^="mailto:"], +.link-mailto { + background: url(mail_icon.gif) center right no-repeat; + padding-right: 18px; +} +#bodyContent a[href ^="news://"] { + background: url(news_icon.png) center right no-repeat; + padding-right: 18px; +} +#bodyContent a[href ^="ftp://"], +.link-ftp { + background: url(file_icon.gif) center right no-repeat; + padding-right: 18px; +} +#bodyContent a[href ^="irc://"], +.link-irc { + background: url(discussionitem_icon.gif) center right no-repeat; + padding-right: 18px; +} +#bodyContent a.external[href $=".ogg"], #bodyContent a.external[href $=".OGG"], +#bodyContent a.external[href $=".mid"], #bodyContent a.external[href $=".MID"], +#bodyContent a.external[href $=".midi"], #bodyContent a.external[href $=".MIDI"], +#bodyContent a.external[href $=".mp3"], #bodyContent a.external[href $=".MP3"], +#bodyContent a.external[href $=".wav"], #bodyContent a.external[href $=".WAV"], +#bodyContent a.external[href $=".wma"], #bodyContent a.external[href $=".WMA"], +.link-audio { + background: url("audio.png") center right no-repeat; + padding-right: 13px; +} +#bodyContent a.external[href $=".ogm"], #bodyContent a.external[href $=".OGM"], +#bodyContent a.external[href $=".avi"], #bodyContent a.external[href $=".AVI"], +#bodyContent a.external[href $=".mpeg"], #bodyContent a.external[href $=".MPEG"], +#bodyContent a.external[href $=".mpg"], #bodyContent a.external[href $=".MPG"], +.link-video { + background: url("video.png") center right no-repeat; + padding-right: 13px; +} +#bodyContent a.external[href $=".pdf"], #bodyContent a.external[href $=".PDF"], +#bodyContent a.external[href *=".pdf#"], #bodyContent a.external[href *=".PDF#"], +#bodyContent a.external[href *=".pdf?"], #bodyContent a.external[href *=".PDF?"], +.link-document { + background: url("document.png") center right no-repeat; + padding-right: 12px; +} + +/* disable interwiki styling */ +#bodyContent a.extiw, +#bodyContent a.extiw:active { + color: #36b; + background: none; + padding: 0; +} +#bodyContent a.external { + color: #36b; +} +/* this can be used in the content area to switch off +special external link styling */ +#bodyContent .plainlinks a { + background: none !important; + padding: 0 !important; +} +/* +** Structural Elements +*/ + +/* +** general portlet styles (elements in the quickbar) +*/ +.portlet { + border: none; + margin: 0 0 .5em; + padding: 0; + float: none; + width: 11.6em; + overflow: hidden; +} +.portlet h4 { + font-size: 95%; + font-weight: normal; + white-space: nowrap; +} +.portlet h5 { + background: transparent; + padding: 0 1em 0 .5em; + display: inline; + height: 1em; + text-transform: lowercase; + font-size: 91%; + font-weight: normal; + white-space: nowrap; +} +.portlet h6 { + background: #ffae2e; + border: 1px solid #2f6fab; + border-style: solid solid none solid; + padding: 0 1em 0 1em; + text-transform: lowercase; + display: block; + font-size: 1em; + height: 1.2em; + font-weight: normal; + white-space: nowrap; +} +.pBody { + font-size: 95%; + background-color: white; + color: black; + border-collapse: collapse; + border: 1px solid #aaa; + padding: 0 .8em .3em .5em; +} +.portlet h1, +.portlet h2, +.portlet h3, +.portlet h4 { + margin: 0; + padding: 0; +} +.portlet ul { + line-height: 1.5em; + list-style-type: square; + list-style-image: url(bullet.gif); + font-size: 95%; +} +.portlet li { + padding: 0; + margin: 0; +} + +/* +** Logo properties +*/ + +@media handheld { + #p-logo { display: none } +} + +/* +** the navigation portlet +*/ + +#p-navigation .pBody { + padding-right: 0; +} + +#p-navigation li.active a, #p-navigation li.active a:hover { + text-decoration: none; + font-weight: bold; +} + + +/* +** Search portlet +*/ +input.searchButton { + margin-top: 1px; + font-size: 95%; +} +#searchGoButton { + padding-left: .5em; + padding-right: .5em; + font-weight: bold; +} +#searchInput { + width: 10.9em; + margin: 0; + font-size: 95%; +} +#p-search .pBody { + padding: .5em .4em .4em .4em; + text-align: center; +} + +/* +** the personal toolbar +*/ +#p-personal ul { + text-transform: lowercase; +} +#p-personal li.active { + font-weight: bold; +} +/* +** the page-related actions- page/talk, edit etc +*/ +#p-cactions .hiddenStructure { + display: none; +} +#p-cactions li a { + text-transform: lowercase; +} + +/* TODO: #t-iscite is only used by the Cite extension, come up with some + * system which allows extensions to add to this file on the fly + */ +#t-ispermalink, #t-iscite { + color: #999; +} +/* +** footer +*/ +#footer { + background-color: white; + border-top: 1px solid #fabd23; + border-bottom: 1px solid #fabd23; + margin: .6em 0 1em 0; + padding: .4em 0 1.2em 0; + text-align: center; + font-size: 90%; +} +#footer li { + display: inline; + margin: 0 1.3em; +} +/* hide from incapable browsers */ +head:first-child+body #footer li { white-space: nowrap; } +#f-poweredbyico, #f-copyrightico { + margin: 0 8px; + position: relative; + top: -2px; /* Bump it up just a tad */ +} +#f-poweredbyico { + float: right; + height: 1%; +} +#f-copyrightico { + float: left; + height: 1%; +} + +/* js pref toc */ +#preftoc { + margin: 0; + padding: 0; + width: 100%; + clear: both; +} +#preftoc li { + background-color: #f0f0f0; + color: #000; +} +#preftoc li.selected { + font-weight: bold; + background-color: #f9f9f9; + border: 1px solid #aaa; + border-bottom: none; + cursor: default; + top: 1px; + padding-top: 2px; + margin-right: -3px; +} +#preftoc > li.selected { + top: 2px; +} +#preftoc a, +#preftoc a:active { + display: block; + color: #000; + padding: 0 .7em; + position: relative; + text-decoration: none; +} +#preftoc li.selected a { + cursor: default; + text-decoration: none; +} +#prefcontrol { + padding-top: 2em; + clear: both; +} +#preferences { + margin: 0; + border: 1px solid #aaa; + clear: both; + padding: 1.5em; + background-color: #F9F9F9; +} +.prefsection { + border: none; + padding: 0; + margin: 0; +} +.prefsection fieldset { + border: 1px solid #aaa; + float: left; + margin-right: 2em; +} +.prefsection legend { + font-weight: bold; +} +.prefsection table, .prefsection legend { + background-color: #F9F9F9; +} +div.prefsectiontip { + font-size: 95%; + margin-top: 0; + background-color: #FFC1C1; + padding: .2em .7em; + clear: both; +} +.btnSavePrefs { + font-weight: bold; + padding-left: .3em; + padding-right: .3em; +} + +.preferences-login { + clear: both; + margin-bottom: 1.5em; +} + +.prefcache { + font-size: 90%; + margin-top: 2em; +} + +div#userloginForm form, +div#userlogin form#userlogin2 { + margin: 0 3em 1em 0; + border: 1px solid #aaa; + clear: both; + padding: 1.5em 2em; + background-color: #f9f9f9; + float: left; +} + +div#userloginForm table, +div#userlogin form#userlogin2 table { + background-color: #f9f9f9; +} + +div#userloginForm h2, +div#userlogin form#userlogin2 h2 { + padding-top: 0; +} + +div#userlogin .captcha { + border: 1px solid #bbb; + padding: 1.5em 2em; + width: 400px; + background-color: white; +} + + +#userloginprompt, #languagelinks { + font-size: 85%; +} + +#login-sectiontip { + font-size: 85%; + line-height: 1.2; + padding-top: 2em; +} + +#userlogin .loginText, #userlogin .loginPassword { + width: 12em; +} + +#userloginlink a, #wpLoginattempt, #wpCreateaccount { + font-weight: bold; +} + +/* more IE fixes */ +/* float/negative margin brokenness */ +* html #footer {margin-top: 0;} +* html #column-content { + display: inline; + margin-bottom: 0; +} +* html div.editsection { font-size: smaller; } +#pagehistory li.selected { position: relative; } + +/* Mac IE 5.0 fix; floated content turns invisible */ +* > html #column-content { + float: none; +} +* > html #column-one { + position: absolute; + left: 0; + top: 0; +} +* > html #footer { + margin-left: 13.2em; +} +.redirectText { + font-size: 150%; + margin: 5px; +} + +.printfooter { + display: none; +} + +.not-patrolled { + background-color: #ffa; +} +div.patrollink { + font-size: 75%; + text-align: right; +} +span.newpage, span.minor, span.searchmatch, span.bot { + font-weight: bold; +} +span.unpatrolled { + font-weight: bold; + color: red; +} + +span.searchmatch { + color: red; +} +.sharedUploadNotice { + font-style: italic; +} + +span.updatedmarker { + color: black; + background-color: #0f0; +} + +table.gallery { + border: 1px solid #ccc; + margin: 2px; + padding: 2px; + background-color: white; +} + +table.gallery tr { + vertical-align: top; +} + +table.gallery td { + vertical-align: top; + background-color: #f9f9f9; + border: solid 2px white; +} + +/* Keep this temporarily so that cached pages will display right */ +table.gallery td.galleryheader { + text-align: center; + font-weight: bold; +} +table.gallery caption { + font-weight: bold; +} + +div.gallerybox { + margin: 2px; + width: 150px; +} + +div.gallerybox div.thumb { + text-align: center; + border: 1px solid #ccc; + margin: 2px; +} + +div.gallerytext { + font-size: 94%; + padding: 2px 4px; +} + +span.comment { + font-style: italic; +} + +span.changedby { + font-size: 95%; +} + +.previewnote { + text-indent: 3em; + color: #c00; + border-bottom: 1px solid #aaa; + padding-bottom: 1em; + margin-bottom: 1em; +} + +.previewnote p { + margin: 0; + padding: 0; +} + +.editExternally { + border: 1px solid gray; + background-color: #ffffff; + padding: 3px; + margin-top: 0.5em; + float: left; + font-size: small; + text-align: center; +} +.editExternallyHelp { + font-style: italic; + color: gray; +} + +li span.deleted, span.history-deleted { + text-decoration: line-through; + color: #888; + font-style: italic; +} + +.toggle { + margin-left: 2em; + text-indent: -2em; +} + +/* Classes for EXIF data display */ +table.mw_metadata { + font-size: 0.8em; + margin-left: 0.5em; + margin-bottom: 0.5em; + width: 300px; +} + +table.mw_metadata caption { + font-weight: bold; +} + +table.mw_metadata th { + font-weight: normal; +} + +table.mw_metadata td { + padding: 0.1em; +} + +table.mw_metadata { + border: none; + border-collapse: collapse; +} + +table.mw_metadata td, table.mw_metadata th { + text-align: center; + border: 1px solid #aaaaaa; + padding-left: 0.1em; + padding-right: 0.1em; +} + +table.mw_metadata th { + background-color: #f9f9f9; +} + +table.mw_metadata td { + background-color: #fcfcfc; +} + +table.collapsed tr.collapsable { + display: none; +} + + +/* filetoc */ +ul#filetoc { + text-align: center; + border: 1px solid #aaaaaa; + background-color: #f9f9f9; + padding: 5px; + font-size: 95%; + margin-bottom: 0.5em; + margin-left: 0; + margin-right: 0; +} + +#filetoc li { + display: inline; + list-style-type: none; + padding-right: 2em; +} + +input#wpSummary { + width: 80%; +} + +/* @bug 1714 */ +input#wpSave, input#wpDiff { + margin-right: 0.33em; +} + +#editform .editOptions { + display: inline; +} + +#wpSave { + font-weight: bold; +} + +/* Classes for article validation */ + +table.revisionform_default { + border: 1px solid #000000; +} + +table.revisionform_focus { + border: 1px solid #000000; + background-color:#00BBFF; +} + +tr.revision_tr_default { + background-color:#EEEEEE; +} + +tr.revision_tr_first { + background-color:#DDDDDD; +} + +p.revision_saved { + color: green; + font-weight:bold; +} + +#mw_trackbacks { + border: solid 1px #bbbbff; + background-color: #eeeeff; + padding: 0.2em; +} + + +/* Allmessages table */ + +#allmessagestable th { + background-color: #b2b2ff; +} + +#allmessagestable tr.orig { + background-color: #ffe2e2; +} + +#allmessagestable tr.new { + background-color: #e2ffe2; +} + +#allmessagestable tr.def { + background-color: #f0f0ff; +} + + +/* noarticletext */ +div.noarticletext { + border: 1px solid #ccc; + background: #fff; + padding: .2em 1em; + color: #000; +} + +div#searchTargetContainer { + left: 10px; + top: 10px; + width: 90%; + background: white; +} + +div#searchTarget { + padding: 3px; + margin: 5px; + background: #F0F0F0; + border: solid 1px blue; +} + +div#searchTarget ul li { + list-style: none; +} + +div#searchTarget ul li:before { + color: orange; + content: "\00BB \0020"; +} + +div.multipageimagenavbox { + border: solid 1px silver; + padding: 4px; + margin: 1em; + -moz-border-radius: 6px; + background: #f0f0f0; +} + +div.multipageimagenavbox div.thumb { + border: none; + margin-left: 2em; + margin-right: 2em; +} + +div.multipageimagenavbox hr { + margin: 6px; +} + +table.multipageimage td { + text-align: center; +} + +/** Special:Version */ + +table#sv-ext, table#sv-hooks { + margin: 1em; + padding:0em; +} + +#sv-ext td, #sv-hooks td, +#sv-ext th, #sv-hooks th { + border: 1px solid #A0A0A0; + padding: 0 0.15em 0 0.15em; +} +#sv-ext th, #sv-hooks th { + background-color: #F0F0F0; + color: black; + padding: 0 0.15em 0 0.15em; +} +tr.sv-space{ + height: 0.8em; + border:none; +} +tr.sv-space td { display: none; } + +/* + Table pager (e.g. Special:Imagelist) + - remove underlines from the navigation link + - collapse borders + - set the borders to outsets (similar to Special:Allmessages) + - remove line wrapping for all td and th, set background color + - restore line wrapping for the last two table cells (description and size) +*/ +.TablePager_nav a { text-decoration: none; } +.TablePager { border-collapse: collapse; } +.TablePager, .TablePager td, .TablePager th { + border: 0.15em solid #777777; + padding: 0 0.15em 0 0.15em; +} +.TablePager th { background-color: #eeeeff } +.TablePager td { background-color: #ffffff } +.TablePager tr:hover td { background-color: #eeeeff } + +.imagelist td, .imagelist th { white-space: nowrap } +.imagelist .TablePager_col_links { background-color: #eeeeff } +.imagelist .TablePager_col_img_description { white-space: normal } +.imagelist th.TablePager_sort { background-color: #ccccff } + +.templatesUsed { margin-top: 1.5em; } + +.mw-summary-preview { + margin: 0.1em 0; +} +@media handheld { + .nonessential { + /* Kill big bulky stuff that will clog up the screen */ + display: none; + } +} + +/** + * Here is some stuff that's ACTUALLY COMMON TO ALL SKINS. + * When the day comes, it can be moved to a *real* common.css. + */ +.mw-plusminus-null { color: #aaa; } +.texvc { direction: ltr; unicode-bidi: embed; } +/* Stop floats from intruding into edit area in previews */ +#toolbar, #wpTextbox1 { clear: both; } \ No newline at end of file diff --git a/pyyaml/YAMLish_files/index.js b/pyyaml/YAMLish_files/index.js new file mode 100644 index 0000000..42c9619 --- /dev/null +++ b/pyyaml/YAMLish_files/index.js @@ -0,0 +1,9 @@ +/* generated javascript */ +var skin = 'monobook'; +var stylepath = '/wiki/skins'; + +/* MediaWiki:Common.js */ +/* Any JavaScript here will be loaded for all users on every page load. */ + +/* MediaWiki:Monobook.js (deprecated; migrate to Common.js!) */ +/* Deprecated; use [[MediaWiki:common.js]] */ \ No newline at end of file diff --git a/pyyaml/YAMLish_files/poweredby_mediawiki_88x31.png b/pyyaml/YAMLish_files/poweredby_mediawiki_88x31.png new file mode 100644 index 0000000..ce1765d Binary files /dev/null and b/pyyaml/YAMLish_files/poweredby_mediawiki_88x31.png differ diff --git a/pyyaml/YAMLish_files/wikibits.js b/pyyaml/YAMLish_files/wikibits.js new file mode 100644 index 0000000..6299e5f --- /dev/null +++ b/pyyaml/YAMLish_files/wikibits.js @@ -0,0 +1,1246 @@ +// MediaWiki JavaScript support functions + +var clientPC = navigator.userAgent.toLowerCase(); // Get client info +var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) + && (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1)); +var is_safari = ((clientPC.indexOf('applewebkit')!=-1) && (clientPC.indexOf('spoofer')==-1)); +var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled )); +// For accesskeys +var is_ff2_win = (clientPC.indexOf('firefox/2')!=-1 || clientPC.indexOf('minefield/3')!=-1) && clientPC.indexOf('windows')!=-1; +var is_ff2_x11 = (clientPC.indexOf('firefox/2')!=-1 || clientPC.indexOf('minefield/3')!=-1) && clientPC.indexOf('x11')!=-1; +if (clientPC.indexOf('opera') != -1) { + var is_opera = true; + var is_opera_preseven = (window.opera && !document.childNodes); + var is_opera_seven = (window.opera && document.childNodes); +} + +// Global external objects used by this script. +/*extern ta, stylepath, skin */ + +// add any onload functions in this hook (please don't hard-code any events in the xhtml source) +var doneOnloadHook; + +if (!window.onloadFuncts) { + var onloadFuncts = []; +} + +function addOnloadHook(hookFunct) { + // Allows add-on scripts to add onload functions + onloadFuncts[onloadFuncts.length] = hookFunct; +} + +function hookEvent(hookName, hookFunct) { + if (window.addEventListener) { + window.addEventListener(hookName, hookFunct, false); + } else if (window.attachEvent) { + window.attachEvent("on" + hookName, hookFunct); + } +} + +// document.write special stylesheet links +if (typeof stylepath != 'undefined' && typeof skin != 'undefined') { + if (is_opera_preseven) { + document.write(''); + } else if (is_opera_seven) { + document.write(''); + } else if (is_khtml) { + document.write(''); + } +} + +if (wgBreakFrames) { + // Un-trap us from framesets + if (window.top != window) { + window.top.location = window.location; + } +} + +// for enhanced RecentChanges +function toggleVisibility(_levelId, _otherId, _linkId) { + var thisLevel = document.getElementById(_levelId); + var otherLevel = document.getElementById(_otherId); + var linkLevel = document.getElementById(_linkId); + if (thisLevel.style.display == 'none') { + thisLevel.style.display = 'block'; + otherLevel.style.display = 'none'; + linkLevel.style.display = 'inline'; + } else { + thisLevel.style.display = 'none'; + otherLevel.style.display = 'inline'; + linkLevel.style.display = 'none'; + } +} + +function historyRadios(parent) { + var inputs = parent.getElementsByTagName('input'); + var radios = []; + for (var i = 0; i < inputs.length; i++) { + if (inputs[i].name == "diff" || inputs[i].name == "oldid") { + radios[radios.length] = inputs[i]; + } + } + return radios; +} + +// check selection and tweak visibility/class onclick +function diffcheck() { + var dli = false; // the li where the diff radio is checked + var oli = false; // the li where the oldid radio is checked + var hf = document.getElementById('pagehistory'); + if (!hf) { + return true; + } + var lis = hf.getElementsByTagName('li'); + for (var i=0;i= 0) ? "-" : "+") + ((tzHour < 10) ? "0" : "") + tzHour + ((tzMin < 10) ? "0" : "") + tzMin; + if (tz != tzString) { + var junk = msg.split('$1'); + document.write(junk[0] + "UTC" + tzString + junk[1]); + } +} + +function unhidetzbutton() { + var tzb = document.getElementById('guesstimezonebutton'); + if (tzb) { + tzb.style.display = 'inline'; + } +} + +// in [-]HH:MM format... +// won't yet work with non-even tzs +function fetchTimezone() { + // FIXME: work around Safari bug + var localclock = new Date(); + // returns negative offset from GMT in minutes + var tzRaw = localclock.getTimezoneOffset(); + var tzHour = Math.floor( Math.abs(tzRaw) / 60); + var tzMin = Math.abs(tzRaw) % 60; + var tzString = ((tzRaw >= 0) ? "-" : "") + ((tzHour < 10) ? "0" : "") + tzHour + + ":" + ((tzMin < 10) ? "0" : "") + tzMin; + return tzString; +} + +function guessTimezone(box) { + document.getElementsByName("wpHourDiff")[0].value = fetchTimezone(); +} + +function showTocToggle() { + if (document.createTextNode) { + // Uses DOM calls to avoid document.write + XHTML issues + + var linkHolder = document.getElementById('toctitle'); + if (!linkHolder) { + return; + } + + var outerSpan = document.createElement('span'); + outerSpan.className = 'toctoggle'; + + var toggleLink = document.createElement('a'); + toggleLink.id = 'togglelink'; + toggleLink.className = 'internal'; + toggleLink.href = 'javascript:toggleToc()'; + toggleLink.appendChild(document.createTextNode(tocHideText)); + + outerSpan.appendChild(document.createTextNode('[')); + outerSpan.appendChild(toggleLink); + outerSpan.appendChild(document.createTextNode(']')); + + linkHolder.appendChild(document.createTextNode(' ')); + linkHolder.appendChild(outerSpan); + + var cookiePos = document.cookie.indexOf("hidetoc="); + if (cookiePos > -1 && document.cookie.charAt(cookiePos + 8) == 1) { + toggleToc(); + } + } +} + +function changeText(el, newText) { + // Safari work around + if (el.innerText) { + el.innerText = newText; + } else if (el.firstChild && el.firstChild.nodeValue) { + el.firstChild.nodeValue = newText; + } +} + +function toggleToc() { + var toc = document.getElementById('toc').getElementsByTagName('ul')[0]; + var toggleLink = document.getElementById('togglelink'); + + if (toc && toggleLink && toc.style.display == 'none') { + changeText(toggleLink, tocHideText); + toc.style.display = 'block'; + document.cookie = "hidetoc=0"; + } else { + changeText(toggleLink, tocShowText); + toc.style.display = 'none'; + document.cookie = "hidetoc=1"; + } +} + +var mwEditButtons = []; +var mwCustomEditButtons = []; // eg to add in MediaWiki:Common.js + +// this function generates the actual toolbar buttons with localized text +// we use it to avoid creating the toolbar where javascript is not enabled +function addButton(imageFile, speedTip, tagOpen, tagClose, sampleText, imageId) { + // Don't generate buttons for browsers which don't fully + // support it. + mwEditButtons[mwEditButtons.length] = + {"imageId": imageId, + "imageFile": imageFile, + "speedTip": speedTip, + "tagOpen": tagOpen, + "tagClose": tagClose, + "sampleText": sampleText}; +} + +// this function generates the actual toolbar buttons with localized text +// we use it to avoid creating the toolbar where javascript is not enabled +function mwInsertEditButton(parent, item) { + var image = document.createElement("img"); + image.width = 23; + image.height = 22; + image.className = "mw-toolbar-editbutton"; + if (item.imageId) image.id = item.imageId; + image.src = item.imageFile; + image.border = 0; + image.alt = item.speedTip; + image.title = item.speedTip; + image.style.cursor = "pointer"; + image.onclick = function() { + insertTags(item.tagOpen, item.tagClose, item.sampleText); + return false; + }; + + parent.appendChild(image); + return true; +} + +function mwSetupToolbar() { + var toolbar = document.getElementById('toolbar'); + if (!toolbar) { return false; } + + var textbox = document.getElementById('wpTextbox1'); + if (!textbox) { return false; } + + // Don't generate buttons for browsers which don't fully + // support it. + if (!document.selection && textbox.selectionStart === null) { + return false; + } + + for (var i = 0; i < mwEditButtons.length; i++) { + mwInsertEditButton(toolbar, mwEditButtons[i]); + } + for (var i = 0; i < mwCustomEditButtons.length; i++) { + mwInsertEditButton(toolbar, mwCustomEditButtons[i]); + } + return true; +} + +function escapeQuotes(text) { + var re = new RegExp("'","g"); + text = text.replace(re,"\\'"); + re = new RegExp("\\n","g"); + text = text.replace(re,"\\n"); + return escapeQuotesHTML(text); +} + +function escapeQuotesHTML(text) { + var re = new RegExp('&',"g"); + text = text.replace(re,"&"); + re = new RegExp('"',"g"); + text = text.replace(re,"""); + re = new RegExp('<',"g"); + text = text.replace(re,"<"); + re = new RegExp('>',"g"); + text = text.replace(re,">"); + return text; +} + +// apply tagOpen/tagClose to selection in textarea, +// use sampleText instead of selection if there is none +// copied and adapted from phpBB +function insertTags(tagOpen, tagClose, sampleText) { + var txtarea; + if (document.editform) { + txtarea = document.editform.wpTextbox1; + } else { + // some alternate form? take the first one we can find + var areas = document.getElementsByTagName('textarea'); + txtarea = areas[0]; + } + + // IE + if (document.selection && !is_gecko) { + var theSelection = document.selection.createRange().text; + if (!theSelection) { + theSelection=sampleText; + } + txtarea.focus(); + if (theSelection.charAt(theSelection.length - 1) == " ") { // exclude ending space char, if any + theSelection = theSelection.substring(0, theSelection.length - 1); + document.selection.createRange().text = tagOpen + theSelection + tagClose + " "; + } else { + document.selection.createRange().text = tagOpen + theSelection + tagClose; + } + + // Mozilla + } else if(txtarea.selectionStart || txtarea.selectionStart == '0') { + var replaced = false; + var startPos = txtarea.selectionStart; + var endPos = txtarea.selectionEnd; + if (endPos-startPos) { + replaced = true; + } + var scrollTop = txtarea.scrollTop; + var myText = (txtarea.value).substring(startPos, endPos); + if (!myText) { + myText=sampleText; + } + var subst; + if (myText.charAt(myText.length - 1) == " ") { // exclude ending space char, if any + subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " "; + } else { + subst = tagOpen + myText + tagClose; + } + txtarea.value = txtarea.value.substring(0, startPos) + subst + + txtarea.value.substring(endPos, txtarea.value.length); + txtarea.focus(); + //set new selection + if (replaced) { + var cPos = startPos+(tagOpen.length+myText.length+tagClose.length); + txtarea.selectionStart = cPos; + txtarea.selectionEnd = cPos; + } else { + txtarea.selectionStart = startPos+tagOpen.length; + txtarea.selectionEnd = startPos+tagOpen.length+myText.length; + } + txtarea.scrollTop = scrollTop; + + // All other browsers get no toolbar. + // There was previously support for a crippled "help" + // bar, but that caused more problems than it solved. + } + // reposition cursor if possible + if (txtarea.createTextRange) { + txtarea.caretPos = document.selection.createRange().duplicate(); + } +} + + +/** + * Set the accesskey prefix based on browser detection. + */ +var tooltipAccessKeyPrefix = 'alt-'; +if (is_opera) { + tooltipAccessKeyPrefix = 'shift-esc-'; +} else if (is_safari + || navigator.userAgent.toLowerCase().indexOf('mac') != -1 + || navigator.userAgent.toLowerCase().indexOf('konqueror') != -1 ) { + tooltipAccessKeyPrefix = 'ctrl-'; +} else if (is_ff2_x11 || is_ff2_win) { + tooltipAccessKeyPrefix = 'alt-shift-'; +} +var tooltipAccessKeyRegexp = /\[(ctrl-)?(alt-)?(shift-)?(esc-)?.\]$/; + +/** + * Add the appropriate prefix to the accesskey shown in the tooltip. + * If the nodeList parameter is given, only those nodes are updated; + * otherwise, all the nodes that will probably have accesskeys by + * default are updated. + * + * @param Array nodeList -- list of elements to update + */ +function updateTooltipAccessKeys( nodeList ) { + if ( !nodeList ) { + // skins without a "column-one" element don't seem to have links with accesskeys either + var columnOne = document.getElementById("column-one"); + if ( columnOne ) + updateTooltipAccessKeys( columnOne.getElementsByTagName("a") ); + // these are rare enough that no such optimization is needed + updateTooltipAccessKeys( document.getElementsByTagName("input") ); + updateTooltipAccessKeys( document.getElementsByTagName("label") ); + return; + } + + for ( var i = 0; i < nodeList.length; i++ ) { + var element = nodeList[i]; + var tip = element.getAttribute("title"); + var key = element.getAttribute("accesskey"); + if ( key && tooltipAccessKeyRegexp.exec(tip) ) { + tip = tip.replace(tooltipAccessKeyRegexp, + "["+tooltipAccessKeyPrefix+key+"]"); + element.setAttribute("title", tip ); + } + } +} + +/** + * Add a link to one of the portlet menus on the page, including: + * + * p-cactions: Content actions (shown as tabs above the main content in Monobook) + * p-personal: Personal tools (shown at the top right of the page in Monobook) + * p-navigation: Navigation + * p-tb: Toolbox + * + * This function exists for the convenience of custom JS authors. All + * but the first three parameters are optional, though providing at + * least an id and a tooltip is recommended. + * + * By default the new link will be added to the end of the list. To + * add the link before a given existing item, pass the DOM node of + * that item (easily obtained with document.getElementById()) as the + * nextnode parameter; to add the link _after_ an existing item, pass + * the node's nextSibling instead. + * + * @param String portlet -- id of the target portlet ("p-cactions", "p-personal", "p-navigation" or "p-tb") + * @param String href -- link URL + * @param String text -- link text (will be automatically lowercased by CSS for p-cactions in Monobook) + * @param String id -- id of the new item, should be unique and preferably have the appropriate prefix ("ca-", "pt-", "n-" or "t-") + * @param String tooltip -- text to show when hovering over the link, without accesskey suffix + * @param String accesskey -- accesskey to activate this link (one character, try to avoid conflicts) + * @param Node nextnode -- the DOM node before which the new item should be added, should be another item in the same list + * + * @return Node -- the DOM node of the new item (an LI element) or null + */ +function addPortletLink(portlet, href, text, id, tooltip, accesskey, nextnode) { + var node = document.getElementById(portlet); + if ( !node ) return null; + node = node.getElementsByTagName( "ul" )[0]; + if ( !node ) return null; + + var link = document.createElement( "a" ); + link.appendChild( document.createTextNode( text ) ); + link.href = href; + + var item = document.createElement( "li" ); + item.appendChild( link ); + if ( id ) item.id = id; + + if ( accesskey ) { + link.setAttribute( "accesskey", accesskey ); + tooltip += " ["+accesskey+"]"; + } + if ( tooltip ) { + link.setAttribute( "title", tooltip ); + } + if ( accesskey && tooltip ) { + updateTooltipAccessKeys( new Array( link ) ); + } + + if ( nextnode && nextnode.parentNode == node ) + node.insertBefore( item, nextnode ); + else + node.appendChild( item ); // IE compatibility (?) + + return item; +} + + +/** + * Set up accesskeys/tooltips from the deprecated ta array. If doId + * is specified, only set up for that id. Note that this function is + * deprecated and will not be supported indefinitely -- use + * updateTooltipAccessKey() instead. + * + * @param mixed doId string or null + */ +function akeytt( doId ) { + // A lot of user scripts (and some of the code below) break if + // ta isn't defined, so we make sure it is. Explictly using + // window.ta avoids a "ta is not defined" error. + if (!window.ta) window.ta = new Array; + + // Make a local, possibly restricted, copy to avoid clobbering + // the original. + var ta; + if ( doId ) { + ta = new Array; + ta[doId] = window.ta[doId]; + } else { + ta = window.ta; + } + + // Now deal with evil deprecated ta + var watchCheckboxExists = document.getElementById( 'wpWatchthis' ) ? true : false; + for (var id in ta) { + var n = document.getElementById(id); + if (n) { + var a = null; + var ak = ''; + // Are we putting accesskey in it + if (ta[id][0].length > 0) { + // Is this object a object? If not assume it's the next child. + + if (n.nodeName.toLowerCase() == "a") { + a = n; + } else { + a = n.childNodes[0]; + } + // Don't add an accesskey for the watch tab if the watch + // checkbox is also available. + if (a && ((id != 'ca-watch' && id != 'ca-unwatch') || !watchCheckboxExists)) { + a.accessKey = ta[id][0]; + ak = ' ['+tooltipAccessKeyPrefix+ta[id][0]+']'; + } + } else { + // We don't care what type the object is when assigning tooltip + a = n; + ak = ''; + } + + if (a) { + a.title = ta[id][1]+ak; + } + } + } +} + +function setupRightClickEdit() { + if (document.getElementsByTagName) { + var spans = document.getElementsByTagName('span'); + for (var i = 0; i < spans.length; i++) { + var el = spans[i]; + if(el.className == 'editsection') { + addRightClickEditHandler(el); + } + } + } +} + +function addRightClickEditHandler(el) { + for (var i = 0; i < el.childNodes.length; i++) { + var link = el.childNodes[i]; + if (link.nodeType == 1 && link.nodeName.toLowerCase() == 'a') { + var editHref = link.getAttribute('href'); + // find the enclosing (parent) header + var prev = el.parentNode; + if (prev && prev.nodeType == 1 && + prev.nodeName.match(/^[Hh][1-6]$/)) { + prev.oncontextmenu = function(e) { + if (!e) { e = window.event; } + // e is now the event in all browsers + var targ; + if (e.target) { targ = e.target; } + else if (e.srcElement) { targ = e.srcElement; } + if (targ.nodeType == 3) { // defeat Safari bug + targ = targ.parentNode; + } + // targ is now the target element + + // We don't want to deprive the noble reader of a context menu + // for the section edit link, do we? (Might want to extend this + // to all 's?) + if (targ.nodeName.toLowerCase() != 'a' + || targ.parentNode.className != 'editsection') { + document.location = editHref; + return false; + } + return true; + }; + } + } + } +} + +var checkboxes; +var lastCheckbox; + +function setupCheckboxShiftClick() { + checkboxes = []; + lastCheckbox = null; + var inputs = document.getElementsByTagName('input'); + addCheckboxClickHandlers(inputs); +} + +function addCheckboxClickHandlers(inputs, start) { + if ( !start) start = 0; + + var finish = start + 250; + if ( finish > inputs.length ) + finish = inputs.length; + + for ( var i = start; i < finish; i++ ) { + var cb = inputs[i]; + if ( !cb.type || cb.type.toLowerCase() != 'checkbox' ) + continue; + cb.index = checkboxes.push(cb) - 1; + cb.onmouseup = checkboxMouseupHandler; + } + + if ( finish < inputs.length ) { + setTimeout( function () { + addCheckboxClickHandlers(inputs, finish); + }, 200 ); + } +} + +function checkboxMouseupHandler(e) { + if (typeof e == 'undefined') { + e = window.event; + } + if ( !e.shiftKey || lastCheckbox === null ) { + lastCheckbox = this.index; + return true; + } + var endState = !this.checked; + if ( is_opera ) { // opera has already toggled the checkbox by this point + endState = !endState; + } + var start, finish; + if ( this.index < lastCheckbox ) { + start = this.index + 1; + finish = lastCheckbox; + } else { + start = lastCheckbox; + finish = this.index - 1; + } + for (var i = start; i <= finish; ++i ) { + checkboxes[i].checked = endState; + } + lastCheckbox = this.index; + return true; +} + +function toggle_element_activation(ida,idb) { + if (!document.getElementById) { + return; + } + document.getElementById(ida).disabled=true; + document.getElementById(idb).disabled=false; +} + +function toggle_element_check(ida,idb) { + if (!document.getElementById) { + return; + } + document.getElementById(ida).checked=true; + document.getElementById(idb).checked=false; +} + +function fillDestFilename(id) { + if (!document.getElementById) { + return; + } + var path = document.getElementById(id).value; + // Find trailing part + var slash = path.lastIndexOf('/'); + var backslash = path.lastIndexOf('\\'); + var fname; + if (slash == -1 && backslash == -1) { + fname = path; + } else if (slash > backslash) { + fname = path.substring(slash+1, 10000); + } else { + fname = path.substring(backslash+1, 10000); + } + + // Capitalise first letter and replace spaces by underscores + fname = fname.charAt(0).toUpperCase().concat(fname.substring(1,10000)).replace(/ /g, '_'); + + // Output result + var destFile = document.getElementById('wpDestFile'); + if (destFile) { + destFile.value = fname; + } +} + +function scrollEditBox() { + var editBoxEl = document.getElementById("wpTextbox1"); + var scrollTopEl = document.getElementById("wpScrolltop"); + var editFormEl = document.getElementById("editform"); + + if (editBoxEl && scrollTopEl) { + if (scrollTopEl.value) { editBoxEl.scrollTop = scrollTopEl.value; } + editFormEl.onsubmit = function() { + document.getElementById("wpScrolltop").value = document.getElementById("wpTextbox1").scrollTop; + }; + } +} + +hookEvent("load", scrollEditBox); + +var allmessages_nodelist = false; +var allmessages_modified = false; +var allmessages_timeout = false; +var allmessages_running = false; + +function allmessagesmodified() { + allmessages_modified = !allmessages_modified; + allmessagesfilter(); +} + +function allmessagesfilter() { + if ( allmessages_timeout ) + window.clearTimeout( allmessages_timeout ); + + if ( !allmessages_running ) + allmessages_timeout = window.setTimeout( 'allmessagesfilter_do();', 500 ); +} + +function allmessagesfilter_do() { + if ( !allmessages_nodelist ) + return; + + var text = document.getElementById('allmessagesinput').value; + var nodef = allmessages_modified; + + allmessages_running = true; + + for ( var name in allmessages_nodelist ) { + var nodes = allmessages_nodelist[name]; + var display = ( name.indexOf( text ) == -1 ? 'none' : '' ); + + for ( var i = 0; i < nodes.length; i++) + nodes[i].style.display = + ( nodes[i].className == "def" && nodef + ? 'none' : display ); + } + + if ( text != document.getElementById('allmessagesinput').value || + nodef != allmessages_modified ) + allmessagesfilter_do(); // repeat + + allmessages_running = false; +} + +function allmessagesfilter_init() { + if ( allmessages_nodelist ) + return; + + var nodelist = new Array(); + var templist = new Array(); + + var table = document.getElementById('allmessagestable'); + if ( !table ) return; + + var rows = document.getElementsByTagName('tr'); + for ( var i = 0; i < rows.length; i++ ) { + var id = rows[i].getAttribute('id') + if ( id && id.substring(0,16) != 'sp-allmessages-r' ) continue; + templist[ id ] = rows[i]; + } + + var spans = table.getElementsByTagName('span'); + for ( var i = 0; i < spans.length; i++ ) { + var id = spans[i].getAttribute('id') + if ( id && id.substring(0,17) != 'sp-allmessages-i-' ) continue; + if ( !spans[i].firstChild || spans[i].firstChild.nodeType != 3 ) continue; + + var nodes = new Array(); + var row1 = templist[ id.replace('i', 'r1') ]; + var row2 = templist[ id.replace('i', 'r2') ]; + + if ( row1 ) nodes[nodes.length] = row1; + if ( row2 ) nodes[nodes.length] = row2; + nodelist[ spans[i].firstChild.nodeValue ] = nodes; + } + + var k = document.getElementById('allmessagesfilter'); + if (k) { k.style.display = ''; } + + allmessages_nodelist = nodelist; +} + +hookEvent( "load", allmessagesfilter_init ); + +/* + Written by Jonathan Snook, http://www.snook.ca/jonathan + Add-ons by Robert Nyman, http://www.robertnyman.com + Author says "The credit comment is all it takes, no license. Go crazy with it!:-)" + From http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ +*/ +function getElementsByClassName(oElm, strTagName, oClassNames){ + var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName); + var arrReturnElements = new Array(); + var arrRegExpClassNames = new Array(); + if(typeof oClassNames == "object"){ + for(var i=0; i 0) { + if (table.tHead && table.tHead.rows.length > 0) { + firstRow = table.tHead.rows[table.tHead.rows.length-1]; + } else { + firstRow = table.rows[0]; + } + } + if (!firstRow) return; + + // We have a first row: assume it's the header, and make its contents clickable links + for (var i = 0; i < firstRow.cells.length; i++) { + var cell = firstRow.cells[i]; + if ((" "+cell.className+" ").indexOf(" unsortable ") == -1) { + cell.innerHTML += '  ↓'; + } + } + if (ts_alternate_row_colors) { + ts_alternate(table); + } +} + +function ts_getInnerText(el) { + if (typeof el == "string") return el; + if (typeof el == "undefined") { return el }; + if (el.innerText) return el.innerText; // Not needed but it is faster + var str = ""; + + var cs = el.childNodes; + var l = cs.length; + for (var i = 0; i < l; i++) { + switch (cs[i].nodeType) { + case 1: //ELEMENT_NODE + str += ts_getInnerText(cs[i]); + break; + case 3: //TEXT_NODE + str += cs[i].nodeValue; + break; + } + } + return str; +} + +function ts_resortTable(lnk) { + // get the span + var span = lnk.getElementsByTagName('span')[0]; + + var td = lnk.parentNode; + var tr = td.parentNode; + var column = td.cellIndex; + + var table = tr.parentNode; + while (table && !(table.tagName && table.tagName.toLowerCase() == 'table')) + table = table.parentNode; + if (!table) return; + + // Work out a type for the column + if (table.rows.length <= 1) return; + + // Skip the first row if that's where the headings are + var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1); + + var itm = ""; + for (var i = rowStart; i < table.rows.length; i++) { + if (table.rows[i].cells.length > column) { + itm = ts_getInnerText(table.rows[i].cells[column]); + itm = itm.replace(/^[\s\xa0]+/, "").replace(/[\s\xa0]+$/, ""); + if (itm != "") break; + } + } + + sortfn = ts_sort_caseinsensitive; + if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/)) + sortfn = ts_sort_date; + if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/)) + sortfn = ts_sort_date; + if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/)) + sortfn = ts_sort_date; + if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro + sortfn = ts_sort_currency; + if (itm.match(/^[\d.,]+\%?$/)) + sortfn = ts_sort_numeric; + + var reverse = (span.getAttribute("sortdir") == 'down'); + + var newRows = new Array(); + for (var j = rowStart; j < table.rows.length; j++) { + var row = table.rows[j]; + var keyText = ts_getInnerText(row.cells[column]); + var oldIndex = (reverse ? -j : j); + + newRows[newRows.length] = new Array(row, keyText, oldIndex); + } + + newRows.sort(sortfn); + + var arrowHTML; + if (reverse) { + arrowHTML = '↓'; + newRows.reverse(); + span.setAttribute('sortdir','up'); + } else { + arrowHTML = '↑'; + span.setAttribute('sortdir','down'); + } + + // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones + // don't do sortbottom rows + for (var i = 0; i < newRows.length; i++) { + if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") == -1) + table.tBodies[0].appendChild(newRows[i][0]); + } + // do sortbottom rows only + for (var i = 0; i < newRows.length; i++) { + if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") != -1) + table.tBodies[0].appendChild(newRows[i][0]); + } + + // Delete any other arrows there may be showing + var spans = getElementsByClassName(tr, "span", "sortarrow"); + for (var i = 0; i < spans.length; i++) { + spans[i].innerHTML = '↓'; + } + span.innerHTML = arrowHTML; + + ts_alternate(table); +} + +function ts_dateToSortKey(date) { + // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX + if (date.length == 11) { + switch (date.substr(3,3).toLowerCase()) { + case "jan": var month = "01"; break; + case "feb": var month = "02"; break; + case "mar": var month = "03"; break; + case "apr": var month = "04"; break; + case "may": var month = "05"; break; + case "jun": var month = "06"; break; + case "jul": var month = "07"; break; + case "aug": var month = "08"; break; + case "sep": var month = "09"; break; + case "oct": var month = "10"; break; + case "nov": var month = "11"; break; + case "dec": var month = "12"; break; + // default: var month = "00"; + } + return date.substr(7,4)+month+date.substr(0,2); + } else if (date.length == 10) { + if (ts_europeandate == false) { + return date.substr(6,4)+date.substr(0,2)+date.substr(3,2); + } else { + return date.substr(6,4)+date.substr(3,2)+date.substr(0,2); + } + } else if (date.length == 8) { + yr = date.substr(6,2); + if (parseInt(yr) < 50) { + yr = '20'+yr; + } else { + yr = '19'+yr; + } + if (ts_europeandate == true) { + return yr+date.substr(3,2)+date.substr(0,2); + } else { + return yr+date.substr(0,2)+date.substr(3,2); + } + } + return "00000000"; +} + +function ts_parseFloat(num) { + if (!num) return 0; + num = parseFloat(num.replace(/,/, "")); + return (isNaN(num) ? 0 : num); +} + +function ts_sort_date(a,b) { + var aa = ts_dateToSortKey(a[1]); + var bb = ts_dateToSortKey(b[1]); + return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); +} + +function ts_sort_currency(a,b) { + var aa = ts_parseFloat(a[1].replace(/[^0-9.]/g,'')); + var bb = ts_parseFloat(b[1].replace(/[^0-9.]/g,'')); + return (aa != bb ? aa - bb : a[2] - b[2]); +} + +function ts_sort_numeric(a,b) { + var aa = ts_parseFloat(a[1]); + var bb = ts_parseFloat(b[1]); + return (aa != bb ? aa - bb : a[2] - b[2]); +} + +function ts_sort_caseinsensitive(a,b) { + var aa = a[1].toLowerCase(); + var bb = b[1].toLowerCase(); + return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); +} + +function ts_sort_default(a,b) { + return (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]); +} + +function ts_alternate(table) { + // Take object table and get all it's tbodies. + var tableBodies = table.getElementsByTagName("tbody"); + // Loop through these tbodies + for (var i = 0; i < tableBodies.length; i++) { + // Take the tbody, and get all it's rows + var tableRows = tableBodies[i].getElementsByTagName("tr"); + // Loop through these rows + // Start at 1 because we want to leave the heading row untouched + for (var j = 0; j < tableRows.length; j++) { + // Check if j is even, and apply classes for both possible results + var oldClasses = tableRows[j].className.split(" "); + var newClassName = ""; + for (var k = 0; k < oldClasses.length; k++) { + if (oldClasses[k] != "" && oldClasses[k] != "even" && oldClasses[k] != "odd") + newClassName += oldClasses[k] + " "; + } + tableRows[j].className = newClassName + (j % 2 == 0 ? "even" : "odd"); + } + } +} + +/* + * End of table sorting code + */ + +function runOnloadHook() { + // don't run anything below this for non-dom browsers + if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName)) { + return; + } + + // set this before running any hooks, since any errors below + // might cause the function to terminate prematurely + doneOnloadHook = true; + + histrowinit(); + unhidetzbutton(); + tabbedprefs(); + updateTooltipAccessKeys( null ); + akeytt( null ); + scrollEditBox(); + setupCheckboxShiftClick(); + sortables_init(); + + // Run any added-on functions + for (var i = 0; i < onloadFuncts.length; i++) { + onloadFuncts[i](); + } +} + +//note: all skins should call runOnloadHook() at the end of html output, +// so the below should be redundant. It's there just in case. +hookEvent("load", runOnloadHook); + +hookEvent("load", mwSetupToolbar); diff --git a/test-perl.pl b/test-perl.pl new file mode 100644 index 0000000..4f2ea3d --- /dev/null +++ b/test-perl.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl -Wall + +use strict; +use warnings; +use Data::YAML::Reader; + +my %test = ( + name => "Unprintables", + in => [ + "---", + "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", + "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", + "- \" !\\\"#\$%&'()*+,-./\"", + "- 0123456789:;<=>?", + "- '\@ABCDEFGHIJKLMNO'", + "- 'PQRSTUVWXYZ[\\]^_'", + "- '`abcdefghijklmno'", + "- 'pqrstuvwxyz{|}~\177'", + "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + "..." + ], + out => [ + "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", + "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", + " !\"#\$%&'()*+,-./", + "0123456789:;<=>?", + "\@ABCDEFGHIJKLMNO", + "PQRSTUVWXYZ[\\]^_", + "`abcdefghijklmno", + "pqrstuvwxyz{|}~\177", + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" + ], + ); + +sub iter { + my $ar = shift; + return sub { + return shift @$ar; + }; +} + +my $yaml = Data::YAML::Reader->new; +my $source = join( "\n", @{ $test{in} } ) . "\n"; + +my $iter = iter( $test{in} ); +my $got = $yaml->read($iter) ; + +use Test::More tests => 1; +unless ( is_deeply $got, $test{out}, "Result matches" ) { + local $Data::Dumper::Useqq = $Data::Dumper::Useqq = 1; + diag( Data::Dumper->Dump( [$got], ['$got'] ) ); + diag( Data::Dumper->Dump( [$test{out}], ['$expected'] ) ); + } \ No newline at end of file diff --git a/test/__init__.py b/test/__init__.py index 9f3cdc6..1f74147 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,20 +1,61 @@ -def TODO(func): - """unittest test method decorator that ignores - exceptions raised by test - - Used to annotate test methods for code that may - not be written yet. Ignores failures in the - annotated test method; fails if the text - unexpectedly succeeds. - """ - def wrapper(*args, **kw): - try: - func(*args, **kw) - succeeded = True - except: - succeeded = False - assert succeeded is False, \ - "%s marked TODO but passed" % func.__name__ - wrapper.__name__ = func.__name__ - wrapper.__doc__ = func.__doc__ - return wrapper +# -*- coding: utf-8 -*- +from __future__ import absolute_import, print_function, unicode_literals +import logging +from test import test_reader, test_input +import yamlish +import unittest +import yaml +logging.basicConfig(level=logging.DEBUG) + +def generate_test_name(source): + out = source.replace(' ', '_').replace(':', '').lower() + return "test_%s" % out + +def create_test(test_src, tested_function): + def do_test_expected(self): + #self.assertEqual(under_test(pair[0]), pair[1]) + if ('skip' in test_src) and test_src['skip']: + logging.info("test_src skipped!") + return + + # rather keep original tests in lists even though we could + # do multiline strings + source = "\n".join(test_src['in']) + "\n" + logging.debug("source = %s", source) + + got = "" + if 'error' in test_src: + self.assertRaises(test_src['error'], tested_function, test_src['in']) + else: + want = test_src['out'] + got = tested_function(test_src['in']) + logging.debug("test_src['out'] = %s", unicode(test_src['out'])) + self.assertEqual(got, want, """Result matches + expected = %s + + observed = %s + """ % (want, got)) + + return do_test_expected + + +def generate_testsuite(test_data, test_case_shell, test_fce): + for in_test in test_data: + if ('skip' in in_test) and in_test['skip']: + logging.info("test %s skipped!", in_test['name']) + continue + name = generate_test_name(in_test['name']) + test_method = create_test (in_test, test_fce) + test_method.__name__ = str('test_%s' % name) + setattr (test_case_shell, test_method.__name__, test_method) + +class TestInput(unittest.TestCase): + pass + +class TestReader(unittest.TestCase): + pass + +if __name__ == "__main__": + generate_testsuite(test_reader.test_data_list, TestReader, yamlish.load) + generate_testsuite(test_input.test_data_list, TestInput, yamlish.load) + unittest.main() diff --git a/test/all_tests.py b/test/all_tests.py index 4a1a532..66e069b 100644 --- a/test/all_tests.py +++ b/test/all_tests.py @@ -1,16 +1,22 @@ +import sys +import os.path +sys.path.insert(0, os.path.realpath(os.path.dirname(__file__) + "/..")) + +import logging +logging.basicConfig(level=logging.INFO) import unittest import test_load import test_input -#import test_reader +import test_reader import test_output -#import test_writer +import test_writer if __name__ == "__main__": loader = unittest.TestLoader() suite = loader.loadTestsFromModule(test_load) - suite.addTests(loader.loadTestsFromModule(test_input)) - #suite.addTests(loader.loadTestsFromModule(test_reader)) - suite.addTests(loader.loadTestsFromModule(test_output)) + #suite.addTests(loader.loadTestsFromModule(test_input)) + suite.addTests(loader.loadTestsFromModule(test_reader)) + #suite.addTests(loader.loadTestsFromModule(test_output)) #suite.addTests(loader.loadTestsFromModule(test_writer)) runner = unittest.TextTestRunner(verbosity=2) diff --git a/test/test_input.py b/test/test_input.py index d221830..d950f86 100644 --- a/test/test_input.py +++ b/test/test_input.py @@ -1,105 +1,66 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals -import logging -import unittest -import yamlish -logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', - level=logging.INFO) - -IN = """ - --- - bill-to: - address: - city: "Royal Oak" - lines: "458 Walkman Dr.\nSuite #292\n" - postal: 48046 - state: MI - family: Dumars - given: Chris - comments: "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n" - date: 2001-01-23 - invoice: 34843 - product: - - - description: Basketball - price: 450.00 - quantity: 4 - sku: BL394D - - - description: "Super Hoop" - price: 2392.00 - quantity: 1 - sku: BL4438H - tax: 251.42 - total: 4443.52 - ... -""" - -OUT = { - 'bill-to': { - 'given': 'Chris', - 'address': { - 'city': 'Royal Oak', - 'postal': '48046', - 'lines': "458 Walkman Dr.\nSuite #292\n", - 'state': 'MI' - }, - 'family': 'Dumars' - }, - 'invoice': '34843', - 'date': '2001-01-23', - 'tax': '251.42', - 'product': [ +test_data_list = [ { - 'sku': 'BL394D', - 'quantity': '4', - 'price': '450.00', - 'description': 'Basketball' - }, - { - 'sku': 'BL4438H', - 'quantity': '1', - 'price': '2392.00', - 'description': 'Super Hoop' - } - ], - 'comments': - "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n", - 'total': '4443.52' -} - -class TestInput(unittest.TestCase): - """FIXME description of this class""" - def test_reader(self): - scalar = IN - source = [ + "name": "Input test", + "in": """--- +bill-to: + address: + city: "Royal Oak" + lines: "458 Walkman Dr.\\nSuite #292\\n" + postal: 48046 + state: MI + family: Dumars + given: Chris +comments: "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\\n" +date: 2001-01-23 +invoice: 34843 +product: + - + description: Basketball + price: 450.00 + quantity: 4 + sku: BL394D + - + description: "Super Hoop" + price: 2392.00 + quantity: 1 + sku: BL4438H +tax: 251.42 +total: 4443.52 +... +""", + 'out': { + 'bill-to': { + 'given': 'Chris', + 'address': { + 'city': 'Royal Oak', + 'postal': 48046, + 'lines': "458 Walkman Dr.\nSuite #292\n", + 'state': 'MI' + }, + 'family': 'Dumars' + }, + 'invoice': 34843, + 'date': '2001-01-23', + 'tax': 251.42, + 'product': [ { - "name": 'Array reference', - "source": IN.split("\n"), + 'sku': 'BL394D', + 'quantity': 4, + 'price': 450.00, + 'description': 'Basketball' }, -# { -# "name": 'Closure', -# "source": sub { shift @lines }, -# }, { - "name": 'Scalar', - "source": IN, + 'sku': 'BL4438H', + 'quantity': 1, + 'price': 2392.00, + 'description': 'Super Hoop' } - ] - - for src in source: - name = src['name'] - yaml = yamlish.Reader() - self.assert_(True, "%s: Created" % name) - self.assert_(isinstance(yaml, yamlish.Reader)) - - #my $got = eval { $yaml -> read($src -> {source}) }; - try: - got = yaml.read(src['source']) - except IOError: # FIXME not sure which one - raise - self.assertEqual(got, OUT, """%s: Result matches - expected = %s - - observed = %s - """ % (name, OUT, got)) + ], + 'comments': + "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n", + 'total': 4443.52 + } + } +] diff --git a/test/test_load.py b/test/test_load.py index 852dd29..a86364b 100644 --- a/test/test_load.py +++ b/test/test_load.py @@ -4,11 +4,9 @@ import unittest class TestBasics(unittest.TestCase): def test_import(self): import yamlish - from yamlish import Reader - self.assert_(True, "Importing Reader.") - from yamlish import Writer - self.assert_(True, "Importing Writer.") - self.assert_(True, + from yamlish import Reader #IGNORE:W0612 + from yamlish import Writer #IGNORE:W0612 + self.assertTrue(yamlish.__version__, "Testing import of yamlish, version %s." % yamlish.__version__) if __name__ == "__main__": diff --git a/test/test_output.py b/test/test_output.py index a8f5a43..ea8d841 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -3,7 +3,7 @@ from __future__ import absolute_import, print_function, unicode_literals import re import unittest import yamlish -from . import TODO +import yaml OUT = [ "---", @@ -74,7 +74,7 @@ destination = [ { "name": 'Array reference', "destination": buf1, - "normalise": (lambda x: buf1), + "normalise": (lambda : buf1), }, # { # "name": 'Closure', @@ -89,15 +89,11 @@ destination = [ ] class TestOuptut(unittest.TestCase): - @TODO def test_output(self): for dest in destination: name = dest['name'] - yaml = yamlish.Writer() - self.assert_(True, "%s: Created" % name) - self.assert_(isinstance(yaml, yamlish.Writer)) - yaml.write(IN, dest[destination]) + yaml.dump(IN, dest) got = dest['normalise']() self.assertEqual(got, OUT, """%s: Result matches diff --git a/test/test_reader.py b/test/test_reader.py index 1694abe..e8d39d1 100644 --- a/test/test_reader.py +++ b/test/test_reader.py @@ -1,10 +1,7 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals -import re -import unittest -import yamlish +import yaml -SCHEDULE = [ +test_data_list = [ { "name": 'Hello World', "in": [ '--- Hello, World', '...', ], @@ -26,45 +23,45 @@ SCHEDULE = [ "out": "Hello, World", }, { - "name": 'Hello World 4', - "in": [ '--- >', ' Hello,', ' World', '...', ], + "name": 'Hello World 5', + "in": [ '--- >', ' Hello,', ' World', '...', ], "out": "Hello, World\n", }, { - "name": 'Hello World 5', - "in": [ '--- >', ' Hello,', ' World', '...', ], - "error": re.compile(r"Missing\s+'[.][.][.]'"), + "name": 'Hello World 6', + "in": [ '--- >', ' Hello,', ' World', '...', ], + "error": yaml.parser.ParserError, }, { "name": 'Simple array', "in": [ '---', '- 1', '- 2', '- 3', '...', ], - "out": [ '1', '2', '3' ], + "out": [ 1, 2, 3 ], }, { "name": 'Mixed array', - "in": [ '---', '- 1', '- \'two\'', '- "three\n"', '...', ], - "out": [ '1', 'two', "three\n" ], + "in": [ '---', '- 1', "- 'two'", r'- "three\n"', '...', ], + "out": [ 1, 'two', "three\n" ], }, { "name": 'Hash in array', - "in": [ '---', '- 1', '- two: 2', '- 3', '...', ], - "out": [ '1', { "two": '2' }, '3' ], + "in": [ '---', ' - 1', ' - two: 2', ' - 3', '...', ], + "out": [ 1, { "two": 2 }, 3 ], }, { "name": 'Hash in array 2', "in": [ '---', '- 1', '- two: 2', ' three: 3', '- 4', '...', ], - "out": [ '1', { "two": '2', "three": '3' }, '4' ], + "out": [ 1, { "two": 2, "three": 3 }, 4 ], }, { "name": 'Nested array', "in": [ '---', '- one', - '-', - ' - two', - ' -', - ' - three', - ' - four', + '- ', + ' - two', + ' - ', + ' - three', + ' - four', '- five', '...', ], @@ -83,8 +80,8 @@ SCHEDULE = [ '...', ], "out": { - "one": { "two": { "three": '3', "four": '4' }, "five": '5' }, - "six": '6' + "one": { "two": { "three": 3, "four": 4 }, "five": 5 }, + "six": 6 }, }, @@ -98,7 +95,7 @@ SCHEDULE = [ ' given : Chris', ' family : Dumars', ' address:', - ' lines: |', + ' lines: | ', ' 458 Walkman Dr.', ' Suite #292', ' city : Royal Oak', @@ -122,36 +119,36 @@ SCHEDULE = [ '...', ], "out": { - "bill - to": { + "bill-to": { "given": 'Chris', "address": { "city": 'Royal Oak', - "postal": '48046', + "postal": 48046, "lines": "458 Walkman Dr.\nSuite #292\n", "state": 'MI' }, "family": 'Dumars' }, - "invoice": '34843', + "invoice": 34843, "date": '2001-01-23', - "tax": '251.42', + "tax": 251.42, "product": [ { "sku": 'BL394D', - "quantity": '4', - "price": '450.00', + "quantity": 4, + "price": 450.00, "description": 'Basketball' }, { "sku": 'BL4438H', - "quantity": '1', - "price": '2392.00', + "quantity": 1, + "price": 2392.00, "description": 'Super Hoop' } ], 'comments': "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n", - "total": '4443.52' + "total": 4443.52 } }, @@ -159,24 +156,25 @@ SCHEDULE = [ { "in": ['...'], "name": 'Regression: empty', - "error": re.compile(r"document\s+header\s+not\s+found") + "error": yaml.parser.ParserError, }, { "in": [ '# comment', '...' ], "name": 'Regression: only_comment', - "error": re.compile(r"document\s+ header\s+ not\s+ found") + "error": yaml.parser.ParserError, }, { + "skip": True, # A corner case, which is apparently not + # clear even from the spec file "out": None, "in": [ '---', '...' ], "name": 'Regression: only_header', - "error": re.compile(r"Premature\s+end", re.I), + "x-error": yaml.parser.ParserError, }, { - "out": None, "in": [ '---', '---', '...' ], "name": 'Regression: two_header', - "error": re.compile(r"Unexpected\s+start", re.I), + "error": yaml.composer.ComposerError, }, { "out": None, @@ -191,7 +189,7 @@ SCHEDULE = [ { "in": [ '--- ~', '---', '...' ], "name": 'Regression: two_undef', - "error": re.compile(r"Missing\s+'[.][.][.]'"), + "error": yaml.composer.ComposerError, }, { "out": 'foo', @@ -206,7 +204,7 @@ SCHEDULE = [ { "in": [ '--- foo', '--- bar', '...' ], "name": 'Regression: two_scalar', - "error": re.compile(r"Missing\s+'[.][.][.]'"), + "error": yaml.composer.ComposerError, }, { "out": ['foo'], @@ -310,49 +308,49 @@ SCHEDULE = [ }, { "name": "Unprintables", + "skip": False, "in": [ - " - - -", - " - \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", - "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", - "- \" !\\\"#\$%&'()*+,-./\"", - "- 0123456789:;<=>?", - "- '\@ABCDEFGHIJKLMNO'", - "- 'PQRSTUVWXYZ[\\]^_'", - "- '`abcdefghijklmno'", - "- 'pqrstuvwxyz{|}~\177'", - "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", - "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", - "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", - "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", - "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", - "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", - "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", - "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", - "..." - ], + "---", + "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", + "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", + "- \" !\\\"#\$%&'()*+,-./\"", + "- 0123456789:;<=>?", + "- '\@ABCDEFGHIJKLMNO'", + "- 'PQRSTUVWXYZ[\\]^_'", + "- '`abcdefghijklmno'", + "- 'pqrstuvwxyz{|}~\177'", + "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + "..."], "out": [ - "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", - "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", - " !\"#\$%&'()*+,-./", - "0123456789:;<=>?", - "\@ABCDEFGHIJKLMNO", - "PQRSTUVWXYZ[\\]^_", - "`abcdefghijklmno", - "pqrstuvwxyz{|}~\177", - "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", - "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", - "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", - "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", - "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", - "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", - "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", - "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" - ], + "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", + "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", + " !\"#\$%&'()*+,-./", + "0123456789:;<=>?", + "\@ABCDEFGHIJKLMNO", + "PQRSTUVWXYZ[\\]^_", + "`abcdefghijklmno", + "pqrstuvwxyz{|}~\177", + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" + ] }, { "name": 'Quoted hash keys', "in": [ - '---', ' "quoted": Magic!', ' "\n\t": newline, tab', '...', + '---', ' "quoted": Magic!', ' "\\n\\t": newline, tab', '...', ], "out": { "quoted": 'Magic!', @@ -360,63 +358,3 @@ SCHEDULE = [ }, }, ] - -# FIXME plan(tests=(len(SCHEDULE) * 5)) - -#sub iter { -# my $ar = shift; -# return sub { -# return shift @$ar; -# }; -#} - -class TestReader(unittest.TestCase): - def test_reader(self): - for test in SCHEDULE: - name = test['name'] - yaml = yamlish.Reader() - self.assert_(True, "%s: Created" % name) - self.assert_(isinstance(yaml, yamlish.Reader)) - - # diag "$name\n"; - - # unless ( $test->{in} ) { - # pass for 1 .. 2; - # use YAML; - # diag "Input for test:\n"; - # diag( Dump( $test->{out} ) ); - # next; - # } - - source = "\n".join([line for line in test['in']]) + "\n" - - try: - got = yaml.read(test['in']) # expecting test['in'] being an iterator - except IOError as exc: # FIXME no idea what - dollar_at = exc - - raw = yaml.get_raw() - - err = test['error'] # RE for testing results - if err: # if we have err, use it - if not err.search(dollar_at): # FIXME $@ (or dollar_at) is described - # in perlvar(1) the error status of the last eval(), which - # means that yaml.read(test['in']) - # if everything is alright, then it is None - self.assertFalse("%s: Error message" % name) - raise Exception(dollar_at) - self.assert_(not got, "%s: No result" % name) - else: - want = test['out'] - self.assert_(not dollar_at, "%s: No error\n%s" % (name, dollar_at)) - - self.assertEqual(got, want, """%s: Result matches - expected = %s - - observed = %s - """ % (name, want, got)) - self.assertEqual(raw, source, """%s: Captured source matches - expected = %s - - observed = %s - """ % (name, raw, source)) diff --git a/test/test_writer.py b/test/test_writer.py index 5b0a8c4..d4ee5ba 100644 --- a/test/test_writer.py +++ b/test/test_writer.py @@ -4,7 +4,7 @@ from __future__ import absolute_import, print_function, unicode_literals import unittest import yamlish -SCHEDULE = [ +test_data_list = [ { "name": 'Simple scalar', "in": 1, @@ -138,50 +138,30 @@ SCHEDULE = [ }, ] -# plan(tests = len(SCHEDULE) * 5) +# plan(tests = len(test_data_list) * 5) class TestWriter(unittest.TestCase): def test_writer(self): - for test in SCHEDULE: + for test in test_data_list: name = test['name'] - yaml = yamlish.Writer() - self.assert_(True, "%s: Created" % name) - self.assert_(isinstance(yaml, yamlish.Writer)) - - got = [] data = test['in'] - try: - yaml.write(data, got) - except Exception as exc: - dollar_at = exc - raise - - # FIXME just to say ... THERE IS NO 'error' key in SCHEDULE!!! - err = test['error'] - if err: - if not err.search(dollar_at): # FIXME $@ (or dollar_at) is described - # in perlvar(1) the error status of the last eval(), which - # means that yaml.read(test['in']) - # if everything is alright, then it is None - self.assertFalse("%s: Error message" % name) - raise Exception(dollar_at) - self.assert_(not got, "%s: No result" % name) + got = [] + # We currently don't throw any exceptions in Writer, so this + # this is always false + if 'error' in test: + self.assertRaises(test['error'], yamlish.write, test['in']) else: want = test['out'] - self.assert_(not dollar_at, "%s: No error\n%s" % (name, dollar_at)) - + yamlish.write(test['in'], got) self.assertEqual(got, want, """%s: Result matches expected = %s observed = %s """ % (name, want, got)) - yr = yamlish.Reader() - # Now try parsing it - parsed = yr.read(got) # FIXME got has an iterator - + parsed = yamlish.load(got) # FIXME got has an iterator self.assertEqual(parsed, data, """%s: Reparse OK expected = %s diff --git a/yamlish.py b/yamlish.py index d26c8be..b3b41c5 100644 --- a/yamlish.py +++ b/yamlish.py @@ -1,87 +1,189 @@ # -*- coding: utf-8 -*- +""" +=head1 NAME + +Data::YAML - Easy YAML serialisation of Perl data structures + +=head1 VERSION + +This document describes Data::YAML version 0.0.6 + +=head1 DESCRIPTION + +In the spirit of L, L and +L provide lightweight, dependency-free YAML +handling. While C is designed principally for working with +configuration files C concentrates on the transparent round- +tripping of YAML serialized Perl data structures. + +As an example of why this distinction matters consider that +C doesn't handle hashes with keys containing non-printable +characters. This is fine for configuration files but likely to cause +problems when handling arbitrary Perl data structures. C +handles exotic hash keys correctly. + +The syntax accepted by C is a subset of YAML. Specifically +it is the same subset of YAML that L produces. See +L for more information. + +=head2 YAML syntax + +Although YAML appears to be a simple language the entire YAML +specification is huge. C implements a small subset of the +complete syntax trading completeness for compactness and simplicity. +This restricted syntax is known (to me at least) as 'YAMLish'. + +These examples demonstrates the full range of supported syntax. + +All YAML documents must begin with '---' and end with a line +containing '...'. + + --- Simple scalar + ... + +Unprintable characters are represented using standard escapes in double +quoted strings. + + --- "\t\x01\x02\n" + ... + +Array and hashes are represented thusly + + --- + - "This" + - "is" + - "an" + - "array" + ... + + --- + This: is + a: hash + ... + +Structures may nest arbitrarily + + --- + - + name: 'Hash one' + value: 1 + - + name: 'Hash two' + value: 2 + ... + +Undef is a tilde + + --- ~ + ... +=head2 Uses + +Use C may be used any time you need to freeze and thaw Perl +data structures into a human readable format. The output from +C should be readable by any YAML parser. + +C was originally written to allow machine-readable +diagnostic information to be passed from test scripts to +L. That means that if you're writing a testing system that +needs to output TAP version 13 or later syntax you might find +C useful. + +Read more about TAP and YAMLish here: L + +=head1 BUGS AND LIMITATIONS + +No bugs have been reported. + +Please report any bugs or feature requests to +C, or through the web interface at +L. + +=head1 AUTHOR + +Andy Armstrong C<< >> + +=head1 LICENCE AND COPYRIGHT + +Copyright (c) 2007, Andy Armstrong C<< >>. All rights reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. See L. + +=head1 DISCLAIMER OF WARRANTY + +BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH +YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR, OR CORRECTION. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE +THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. +""" + +import logging import yaml -import pprint __version__ = "0.1" -IN = """ ---- -bill-to: - address: - city: "Royal Oak" - lines: "458 Walkman Dr.\nSuite #292\n" - postal: 48046 - state: MI - family: Dumars - given: Chris -comments: "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n" -date: 2001-01-23 -invoice: 34843 -product: - - - description: Basketball - price: 450.00 - quantity: 4 - sku: BL394D - - - description: "Super Hoop" - price: 2392.00 - quantity: 1 - sku: BL4438H -tax: 251.42 -total: 4443.52 -... -""" +class YamlishLoader(yaml.reader.Reader, yaml.scanner.Scanner, + yaml.parser.Parser, yaml.composer.Composer, + yaml.constructor.SafeConstructor, yaml.resolver.Resolver): + def __init__(self, stream): + yaml.reader.Reader.__init__(self, stream) + yaml.scanner.Scanner.__init__(self) + yaml.parser.Parser.__init__(self) + yaml.composer.Composer.__init__(self) + yaml.constructor.SafeConstructor.__init__(self) + yaml.resolver.Resolver.__init__(self) + + @classmethod + def remove_implicit_resolver(cls, tag): + if not 'yaml_implicit_resolvers' in cls.__dict__: + cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy() + for key in cls.yaml_implicit_resolvers: + resolvers_set = cls.yaml_implicit_resolvers[key] + for idx in range(len(resolvers_set)): + if resolvers_set[idx][0] == tag: + del resolvers_set[idx] + if len(resolvers_set) == 0: + del cls.yaml_implicit_resolvers[key] + +YamlishLoader.remove_implicit_resolver(u'tag:yaml.org,2002:timestamp') + +def load(source): + out = None + logging.debug("instr:\n%s", source) + if isinstance(source, (str, unicode)): + out = yaml.load(source, Loader=YamlishLoader) + logging.debug("out (string) = %s", out) + elif hasattr(source, "__iter__"): + instr = "\n".join(source) + out = yaml.load(instr, Loader=YamlishLoader) + logging.debug("out (iter) = %s", out) + return out + +def dump(source, destination): + if isinstance(destination, (str, unicode)): + with open(destination, "w") as outf: + dump(source, outf) + elif isinstance(destination, file): + yaml.dump(source, destination, canonical=False, + default_flow_style=False, default_style=False) -OUT = { - 'bill-to': { - 'given': 'Chris', - 'address': { - 'city': 'Royal Oak', - 'postal': '48046', - 'lines': "458 Walkman Dr.\nSuite #292\n", - 'state': 'MI' - }, - 'family': 'Dumars' - }, - 'invoice': '34843', - 'date': '2001-01-23', - 'tax': '251.42', - 'product': [ - { - 'sku': 'BL394D', - 'quantity': '4', - 'price': '450.00', - 'description': 'Basketball' - }, - { - 'sku': 'BL4438H', - 'quantity': '1', - 'price': '2392.00', - 'description': 'Super Hoop' - } - ], - 'comments': - "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n", - 'total': '4443.52' -} - -class Reader(object): - def __init__(self): - pass - - def get_raw(self): - pass - - def read(self, source): - pass - -class Writer(object): - def __init__(self): - pass - - def write(self, source, destination): - pass - -#print yaml.dump(OUT, canonical=False, default_flow_style=False, default_style=False) +def dumps(source): + return yaml.dump(source, canonical=False, + default_flow_style=False, default_style=False) -- cgit