Commits

ZHUO Qiang committed a21a909

add html5 schema validation

  • Participants
  • Parent commits 2710607

Comments (0)

Files changed (41)

  (cons '("\\.\\(xml\\|html\\|zcml\\)" . nxml-mode)
        auto-mode-alist))
 
+(setq nxml-slash-auto-complete-flag t)
+(eval-after-load "rng-loc"
+  '(add-to-list 'rng-schema-locating-files (qiang-in-emacs-directory "lisp/html5-el/schemas.xml")))
+(require 'whattf-dt)
 
 ;; Markdown Mode
 (autoload 'markdown-mode "markdown-mode"

File lisp/html5-el/LICENSE

+Copyright (C) 2009, 2010 Edward O'Connor
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File lisp/html5-el/Makefile

+# Copyright (C) 2009, 2010  Edward O'Connor
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+EMACS=emacs
+
+dummy:
+	echo "USAGE: $(make) [html5-ncr.el]"
+
+clean:
+	rm -f language-subtag-registry parsing-algorithm *~ *.elc
+
+distclean:
+	rm -rf relaxng webapps
+
+parsing-algorithm: webapps tools/extract-parsing-algorithm.py
+	python tools/extract-parsing-algorithm.py < webapps/source > parsing-algorithm
+
+html5-ncr.el: webapps tools/build-ncr.py
+	python tools/build-ncr.py webapps/entities-legacy.inc webapps/entities-unicode.inc > $@
+
+html5-langs.el: tools/build-langs.py language-subtag-registry
+	python tools/build-langs.py language-subtag-registry > html5-langs.el
+
+test: html5lib/testdata/tokenizer/test1.test
+	@$(EMACS) -batch -l h5-maint.el -f h5-run-tests html5lib/testdata/tokenizer/*.test
+
+.el.elc:
+	@$(EMACS) -batch -f batch-byte-compile $*.el \
+		|| (echo "Perhaps you should specifcy LOAD_PATH to make?" \
+		"(e.g. \"gmake LOAD_PATH=~/elisp\".)" \
+		&& echo "Please see README for compilation instructions." \
+		&& exit 1)
+
+## External repositories
+
+# (non-normative) RELAX NG schema for HTML5
+relaxng:
+	svn co http://whattf.svn.cvsdude.com/syntax/trunk/relaxng/ relaxng
+# The HTML5 spec source
+webapps:
+	svn co http://svn.whatwg.org/webapps webapps
+# Two- and three-letter language codes
+language-subtag-registry:
+	curl -O http://www.iana.org/assignments/language-subtag-registry
+html5lib/testdata/tokenizer/test1.test: html5lib
+html5lib:
+	hg clone https://html5lib.googlecode.com/hg/ html5lib
+
+update:
+	cd relaxng; svn up
+	cd webapps; svn up

File lisp/html5-el/README.markdown

+# html5-el
+
+This is an umbrella repository for various projects of mine involving
+working with HTML5 in Emacs Lisp.
+
+## Edit XHTML5 documents with `nxml-mode`
+
+This provides the ability to use `nxml-mode` to edit XHTML5 documents
+with RELAX NG validation.
+
+### How to use
+
+First, you'll need to fetch the RELAX NG schema from the WHAT Task Force
+subversion repository; a simple `make relaxng` in this directory should
+do the trick.
+
+Next, you'll need to add this directory to your `load-path`. Let's
+assume you've placed it in `~/code/html5-el/`.
+
+    (add-to-list 'load-path "~/code/html5-el/")
+
+Finally, wire this stuff into `nxml-mode` like so, altering the path to
+`schemas.xml` appropriately.
+
+    (eval-after-load "rng-loc"
+      '(add-to-list 'rng-schema-locating-files "~/code/html5-el/schemas.xml"))
+
+    (require 'whattf-dt)
+
+## Experimental Emacs Lisp HTML5 tokenizer (`html5-tok.el`)
+
+This is an implementation of the HTML5 tokenizer in Emacs Lisp. The API
+is relatively simple: with point at the location in a buffer where you'd
+like to start tokenizing, call `html5-tok-forward` to move forward one
+token. The token moved over is returned.
+
+Despite the fact that all the tokenizer states are implemented, this is
+very early on in its life and the interface is likely to change
+significantly.

File lisp/html5-el/h5-maint.el

+(add-to-list 'load-path default-directory)
+(mapc (lambda (dir) (add-to-list 'load-path dir))
+      (parse-colon-path (getenv "LOAD_PATH")))
+
+(require 'json)
+(require 'html5-tok)
+
+(defun h5-explore-text-properties ()
+  (when (< (point) (point-max))
+    (describe-text-properties (point))))
+
+(define-minor-mode h5-explore-text-properties-mode
+  "Explore the text properties in this buffer."
+  nil " xtp" nil
+  (if explore-text-properties-mode
+      (add-hook 'post-command-hook 'h5-explore-text-properties nil t)
+    (remove-hook 'post-command-hook 'h5-explore-text-properties t)))
+
+(defun h5-munge-state-name (state-name)
+  (intern (format "h5-%s"
+                  (mapconcat 'identity (split-string state-name) "-"))))
+
+(defsubst h5-test-input (test)
+  (cdr (assoc 'input test)))
+(defsubst h5-test-initial-states (test)
+  (cdr (assoc 'initialStates test)))
+(defsubst h5-test-last-start-tag (test)
+  (cdr (assoc 'lastStartTag test)))
+(defsubst h5-test-output (test)
+  (cdr (assoc 'output test)))
+(defsubst h5-test-description (test)
+  (cdr (assoc 'description test)))
+
+(defun h5-coalesce-chars (in-toks)
+  (let ((out-toks '())
+        (in-charrun nil)
+        (charrun '()))
+    (dolist (tok in-toks)
+      (cond
+       ((and (numberp tok) (not in-charrun))
+        (setq in-charrun t
+              charrun '())
+        (push tok charrun))
+       ((and (numberp tok) in-charrun)
+        (push tok charrun))
+       (in-charrun
+        (push (apply 'string (nreverse charrun)) out-toks)
+        (push tok out-toks)
+        (setq in-charrun nil
+              charrun '()))
+       (t
+        (push tok out-toks))))
+    (if in-charrun
+        (push (apply 'string (nreverse charrun)) out-toks))
+    (nreverse out-toks)))
+
+(defun h5-compare-doctype-to-expected (doctype expected)
+  (and (listp expected)
+       (string-equal (nth 0 expected) "DOCTYPE")
+       (let ((expected-name (nth 1 expected))
+             (expected-public-id (or (nth 2 expected) 'missing))
+             (expected-system-id (or (nth 3 expected) 'missing))
+             (expected-force-quirks (nth 4 expected)))
+         (and
+          (string-equal (h5-doctype-token-name actual) expected-name)
+          (equal (h5-doctype-token-public-id actual) expected-public-id)
+          (equal (h5-doctype-token-system-id actual) expected-system-id)
+          (equal (h5-doctype-token-force-quirks actual)
+                 expected-force-quirks)))))
+
+(defun h5-compare-attr (actual expected)
+  (and (consp expected)
+       (h5-attr-p actual)
+       (string-equal (h5-attr-name actual)
+                     (symbol-name (car expected)))
+       (string-equal (h5-attr-value actual)
+                     (cdr expected))))
+
+(defun h5-compare-attrs (actual expected)
+  (and (listp actual)
+       (listp expected)
+       (eq (length actual) (length expected))
+       (every 'identity
+              (loop for a-attr in actual
+                    for e-attr in expected
+                    collect (h5-compare-attr a-attr e-attr)))))
+
+(defun h5-compare-start-tag-to-expected (start-tag expected)
+  (and (listp expected)
+       (string-equal (nth 0 expected) "StartTag")
+       (string-equal (h5-tag-token-name start-tag) (nth 1 expected))
+       (h5-compare-attrs (h5-start-tag-token-attributes start-tag)
+                         (nth 2 expected))))
+
+(defun h5-compare-token-to-expected (actual expected)
+  (cond ((and
+          (stringp actual)
+          (listp expected)
+          (string-equal (car expected) "Character"))
+         (string-equal actual (cadr expected)))
+        ((h5-end-tag-token-p actual)
+         (and (listp expected)
+              (string-equal (car expected) "EndTag")
+              (string-equal (h5-tag-token-name actual)
+                            (cadr expected))))
+        ((eq actual :parse-error)
+         (and (stringp expected)
+              (string-equal expected "ParseError")))
+        ((h5-doctype-token-p actual)
+         (h5-compare-doctype-to-expected actual expected))
+        ((h5-start-tag-token-p actual)
+         (h5-compare-start-tag-to-expected actual expected))
+        ((h5-comment-token-p actual)
+         (and (listp expected)
+              (string-equal (car expected) "Comment")
+              (string-equal (h5-comment-token-data actual)
+                            (cadr expected))))
+        (t
+         ;; (princ (make-string 72 ?-))
+         ;; (terpri)
+         ;; (princ (format "actual %S\n" actual))
+         ;; (princ (format "expected %S\n" expected))
+         (error "comparing apples and oranges?"))))
+
+(defun h5-compare-tokens-to-expected-output (actual expected)
+  (every 'identity
+         (loop for actual-tok in actual
+               for expected-tok in expected
+               collect (h5-compare-token-to-expected actual-tok expected-tok))))
+
+(defun h5-run-test-1 (test initial-state)
+  (let ((tokens '())
+        (token t)
+        (passed nil)
+        (h5-last-start-tag-emitted
+         (if (h5-test-last-start-tag test)
+             (make-h5-start-tag-token
+              :name (h5-test-last-start-tag test))
+           nil)))
+    (setq initial-state
+          (if initial-state
+              (h5-munge-state-name initial-state)
+            nil))
+    (with-temp-buffer
+      (insert (h5-test-input test))
+      (goto-char (point-min))
+      (while (not (eq token :eof))
+        (setq token (html5-tok-forward nil initial-state))
+        (setq initial-state nil)
+        (unless (eq token :eof)
+          (push token tokens)))
+      (setq tokens (h5-coalesce-chars (nreverse tokens)))
+      (setq passed
+            (h5-compare-tokens-to-expected-output tokens (h5-test-output test))))
+    passed))
+
+(defun h5-run-test (test)
+  (let ((initial-states (or (h5-test-initial-states test) (list "data state"))))
+    (condition-case e
+        (every 'identity
+               (mapcar
+                (lambda (initial-state)
+                  (h5-run-test-1 test initial-state))
+                initial-states))
+      (error
+       ;; (princ (format "Blew up: %S!\n" e))
+       nil))))
+
+(defun h5-run-tests ()
+  (let ((total 0)
+        (passed 0)
+        (PASSED "\033[32;1mPASS\033[0m")
+        (FAILED "\033[31;1mFAIL\033[0m"))
+    (dolist (testfile command-line-args-left)
+      (princ (format "Running tests from %s:\n"
+                     (file-name-nondirectory testfile)))
+      (let ((testdata
+             (let ((json-object-type 'alist)
+                   (json-array-type 'list))
+               (json-read-file testfile))))
+        (dolist (test (cdr (assoc 'tests testdata)))
+          (incf total)
+          (princ (format "\t'%s': %s\n"
+                         (h5-test-description test)
+                         (if (h5-run-test test)
+                             (prog1 PASSED (incf passed))
+                           FAILED))))))
+    (princ (format "Passed %d out of %d tests (%02.1f%%)"
+                   passed total
+                   (* 100 (/ (float passed) (float total))))))
+  (setq command-line-args-left nil))

File lisp/html5-el/html5-langs.el

+;;; html5-langs.el --- Language tags
+
+;; A derivative work of the IANA language subtag registry, which, as far
+;; as I can tell, is in the public domain.
+
+;; Author: Edward O'Connor <hober0@gmail.com>
+;; Keywords: hypermedia, wp
+
+;;; Commentary:
+
+;; List of language tags.
+
+;;; Code:
+
+(defvar html5-language-tags
+  '(
+"aa"
+"ab"
+"ae"
+"af"
+"ak"
+"am"
+"an"
+"ar"
+"as"
+"av"
+"ay"
+"az"
+"ba"
+"be"
+"bg"
+"bh"
+"bi"
+"bm"
+"bn"
+"bo"
+"br"
+"bs"
+"ca"
+"ce"
+"ch"
+"co"
+"cr"
+"cs"
+"cu"
+"cv"
+"cy"
+"da"
+"de"
+"dv"
+"dz"
+"ee"
+"el"
+"en"
+"eo"
+"es"
+"et"
+"eu"
+"fa"
+"ff"
+"fi"
+"fj"
+"fo"
+"fr"
+"fy"
+"ga"
+"gd"
+"gl"
+"gn"
+"gu"
+"gv"
+"ha"
+"he"
+"hi"
+"ho"
+"hr"
+"ht"
+"hu"
+"hy"
+"hz"
+"ia"
+"id"
+"ie"
+"ig"
+"ii"
+"ik"
+"in"
+"io"
+"is"
+"it"
+"iu"
+"iw"
+"ja"
+"ji"
+"jv"
+"jw"
+"ka"
+"kg"
+"ki"
+"kj"
+"kk"
+"kl"
+"km"
+"kn"
+"ko"
+"kr"
+"ks"
+"ku"
+"kv"
+"kw"
+"ky"
+"la"
+"lb"
+"lg"
+"li"
+"ln"
+"lo"
+"lt"
+"lu"
+"lv"
+"mg"
+"mh"
+"mi"
+"mk"
+"ml"
+"mn"
+"mo"
+"mr"
+"ms"
+"mt"
+"my"
+"na"
+"nb"
+"nd"
+"ne"
+"ng"
+"nl"
+"nn"
+"no"
+"nr"
+"nv"
+"ny"
+"oc"
+"oj"
+"om"
+"or"
+"os"
+"pa"
+"pi"
+"pl"
+"ps"
+"pt"
+"qu"
+"rm"
+"rn"
+"ro"
+"ru"
+"rw"
+"sa"
+"sc"
+"sd"
+"se"
+"sg"
+"sh"
+"si"
+"sk"
+"sl"
+"sm"
+"sn"
+"so"
+"sq"
+"sr"
+"ss"
+"st"
+"su"
+"sv"
+"sw"
+"ta"
+"te"
+"tg"
+"th"
+"ti"
+"tk"
+"tl"
+"tn"
+"to"
+"tr"
+"ts"
+"tt"
+"tw"
+"ty"
+"ug"
+"uk"
+"ur"
+"uz"
+"ve"
+"vi"
+"vo"
+"wa"
+"wo"
+"xh"
+"yi"
+"yo"
+"za"
+"zh"
+"zu"
+"aaa"
+"aab"
+"aac"
+"aad"
+"aae"
+"aaf"
+"aag"
+"aah"
+"aai"
+"aak"
+"aal"
+"aam"
+"aan"
+"aao"
+"aap"
+"aaq"
+"aas"
+"aat"
+"aau"
+"aav"
+"aaw"
+"aax"
+"aaz"
+"aba"
+"abb"
+"abc"
+"abd"
+"abe"
+"abf"
+"abg"
+"abh"
+"abi"
+"abj"
+"abl"
+"abm"
+"abn"
+"abo"
+"abp"
+"abq"
+"abr"
+"abs"
+"abt"
+"abu"
+"abv"
+"abw"
+"abx"
+"aby"
+"abz"
+"aca"
+"acb"
+"acd"
+"ace"
+"acf"
+"ach"
+"aci"
+"ack"
+"acl"
+"acm"
+"acn"
+"acp"
+"acq"
+"acr"
+"acs"
+"act"
+"acu"
+"acv"
+"acw"
+"acx"
+"acy"
+"acz"
+"ada"
+"adb"
+"add"
+"ade"
+"adf"
+"adg"
+"adh"
+"adi"
+"adj"
+"adl"
+"adn"
+"ado"
+"adp"
+"adq"
+"adr"
+"ads"
+"adt"
+"adu"
+"adw"
+"adx"
+"ady"
+"adz"
+"aea"
+"aeb"
+"aec"
+"aed"
+"aee"
+"aek"
+"ael"
+"aem"
+"aen"
+"aeq"
+"aer"
+"aes"
+"aeu"
+"aew"
+"aey"
+"aez"
+"afa"
+"afb"
+"afd"
+"afe"
+"afg"
+"afh"
+"afi"
+"afk"
+"afn"
+"afo"
+"afp"
+"afs"
+"aft"
+"afu"
+"afz"
+"aga"
+"agb"
+"agc"
+"agd"
+"age"
+"agf"
+"agg"
+"agh"
+"agi"
+"agj"
+"agk"
+"agl"
+"agm"
+"agn"
+"ago"
+"agp"
+"agq"
+"agr"
+"ags"
+"agt"
+"agu"
+"agv"
+"agw"
+"agx"
+"agy"
+"agz"
+"aha"
+"ahb"
+"ahg"
+"ahh"
+"ahi"
+"ahk"
+"ahl"
+"ahm"
+"ahn"
+"aho"
+"ahp"
+"ahr"
+"ahs"
+"aht"
+"aia"
+"aib"
+"aic"
+"aid"
+"aie"
+"aif"
+"aig"
+"aih"
+"aii"
+"aij"
+"aik"
+"ail"
+"aim"
+"ain"
+"aio"
+"aip"
+"aiq"
+"air"
+"ais"
+"ait"
+"aiw"
+"aix"
+"aiy"
+"aja"
+"ajg"
+"aji"
+"ajp"
+"ajt"
+"aju"
+"ajw"
+"ajz"
+"akb"
+"akc"
+"akd"
+"ake"
+"akf"
+"akg"
+"akh"
+"aki"
+"akj"
+"akk"
+"akl"
+"akm"
+"ako"
+"akp"
+"akq"
+"akr"
+"aks"
+"akt"
+"aku"
+"akv"
+"akw"
+"akx"
+"aky"
+"akz"
+"ala"
+"alc"
+"ald"
+"ale"
+"alf"
+"alg"
+"alh"
+"ali"
+"alj"
+"alk"
+"all"
+"alm"
+"aln"
+"alo"
+"alp"
+"alq"
+"alr"
+"als"
+"alt"
+"alu"
+"alv"
+"alw"
+"alx"
+"aly"
+"alz"
+"ama"
+"amb"
+"amc"
+"ame"
+"amf"
+"amg"
+"ami"
+"amj"
+"amk"
+"aml"
+"amm"
+"amn"
+"amo"
+"amp"
+"amq"
+"amr"
+"ams"
+"amt"
+"amu"
+"amv"
+"amw"
+"amx"
+"amy"
+"amz"
+"ana"
+"anb"
+"anc"
+"and"
+"ane"
+"anf"
+"ang"
+"anh"
+"ani"
+"anj"
+"ank"
+"anl"
+"anm"
+"ann"
+"ano"
+"anp"
+"anq"
+"anr"
+"ans"
+"ant"
+"anu"
+"anv"
+"anw"
+"anx"
+"any"
+"anz"
+"aoa"
+"aob"
+"aoc"
+"aod"
+"aoe"
+"aof"
+"aog"
+"aoh"
+"aoi"
+"aoj"
+"aok"
+"aol"
+"aom"
+"aon"
+"aor"
+"aos"
+"aot"
+"aox"
+"aoz"
+"apa"
+"apb"
+"apc"
+"apd"
+"ape"
+"apf"
+"apg"
+"aph"
+"api"
+"apj"
+"apk"
+"apl"
+"apm"
+"apn"
+"apo"
+"app"
+"apq"
+"apr"
+"aps"
+"apt"
+"apu"
+"apv"
+"apw"
+"apx"
+"apy"
+"apz"
+"aqa"
+"aqc"
+"aqg"
+"aql"
+"aqm"
+"aqn"
+"aqp"
+"aqr"
+"aqz"
+"arb"
+"arc"
+"ard"
+"are"
+"arh"
+"ari"
+"arj"
+"ark"
+"arl"
+"arn"
+"aro"
+"arp"
+"arq"
+"arr"
+"ars"
+"art"
+"aru"
+"arv"
+"arw"
+"arx"
+"ary"
+"arz"
+"asa"
+"asb"
+"asc"
+"asd"
+"ase"
+"asf"
+"asg"
+"ash"
+"asi"
+"asj"
+"ask"
+"asl"
+"asn"
+"aso"
+"asp"
+"asq"
+"asr"
+"ass"
+"ast"
+"asu"
+"asv"
+"asw"
+"asx"
+"asy"
+"asz"
+"ata"
+"atb"
+"atc"
+"atd"
+"ate"
+"atg"
+"ath"
+"ati"
+"atj"
+"atk"
+"atl"
+"atm"
+"atn"
+"ato"
+"atp"
+"atq"
+"atr"
+"ats"
+"att"
+"atu"
+"atv"
+"atw"
+"atx"
+"aty"
+"atz"
+"aua"
+"aub"
+"auc"
+"aud"
+"aue"
+"auf"
+"aug"
+"auh"
+"aui"
+"auj"
+"auk"
+"aul"
+"aum"
+"aun"
+"auo"
+"aup"
+"auq"
+"aur"
+"aus"
+"aut"
+"auu"
+"auw"
+"aux"
+"auy"
+"auz"
+"avb"
+"avd"
+"avi"
+"avk"
+"avl"
+"avn"
+"avo"
+"avs"
+"avt"
+"avu"
+"avv"
+"awa"
+"awb"
+"awc"
+"awd"
+"awe"
+"awh"
+"awi"
+"awk"
+"awm"
+"awn"
+"awo"
+"awr"
+"aws"
+"awt"
+"awu"
+"awv"
+"aww"
+"awx"
+"awy"
+"axb"
+"axg"
+"axk"
+"axm"
+"axx"
+"aya"
+"ayb"
+"ayc"
+"ayd"
+"aye"
+"ayg"
+"ayh"
+"ayi"
+"ayk"
+"ayl"
+"ayn"
+"ayo"
+"ayp"
+"ayq"
+"ayr"
+"ays"
+"ayt"
+"ayu"
+"ayx"
+"ayy"
+"ayz"
+"aza"
+"azb"
+"azc"
+"azg"
+"azj"
+"azm"
+"azo"
+"azt"
+"azz"
+"baa"
+"bab"
+"bac"
+"bad"
+"bae"
+"baf"
+"bag"
+"bah"
+"bai"
+"baj"
+"bal"
+"ban"
+"bao"
+"bap"
+"bar"
+"bas"
+"bat"
+"bau"
+"bav"
+"baw"
+"bax"
+"bay"
+"baz"
+"bba"
+"bbb"
+"bbc"
+"bbd"
+"bbe"
+"bbf"
+"bbg"
+"bbh"
+"bbi"
+"bbj"
+"bbk"
+"bbl"
+"bbm"
+"bbn"
+"bbo"
+"bbp"
+"bbq"
+"bbr"
+"bbs"
+"bbt"
+"bbu"
+"bbv"
+"bbw"
+"bbx"
+"bby"
+"bbz"
+"bca"
+"bcb"
+"bcc"
+"bcd"
+"bce"
+"bcf"
+"bcg"
+"bch"
+"bci"
+"bcj"
+"bck"
+"bcl"
+"bcm"
+"bcn"
+"bco"
+"bcp"
+"bcq"
+"bcr"
+"bcs"
+"bct"
+"bcu"
+"bcv"
+"bcw"
+"bcy"
+"bcz"
+"bda"
+"bdb"
+"bdc"
+"bdd"
+"bde"
+"bdf"
+"bdg"
+"bdh"
+"bdi"
+"bdj"
+"bdk"
+"bdl"
+"bdm"
+"bdn"
+"bdo"
+"bdp"
+"bdq"
+"bdr"
+"bds"
+"bdt"
+"bdu"
+"bdv"
+"bdw"
+"bdx"
+"bdy"
+"bdz"
+"bea"
+"beb"
+"bec"
+"bed"
+"bee"
+"bef"
+"beg"
+"beh"
+"bei"
+"bej"
+"bek"
+"bem"
+"beo"
+"bep"
+"beq"
+"ber"
+"bes"
+"bet"
+"beu"
+"bev"
+"bew"
+"bex"
+"bey"
+"bez"
+"bfa"
+"bfb"
+"bfc"
+"bfd"
+"bfe"
+"bff"
+"bfg"
+"bfh"
+"bfi"
+"bfj"
+"bfk"
+"bfl"
+"bfm"
+"bfn"
+"bfo"
+"bfp"
+"bfq"
+"bfr"
+"bfs"
+"bft"
+"bfu"
+"bfw"
+"bfx"
+"bfy"
+"bfz"
+"bga"
+"bgb"
+"bgc"
+"bgd"
+"bge"
+"bgf"
+"bgg"
+"bgi"
+"bgj"
+"bgk"
+"bgl"
+"bgm"
+"bgn"
+"bgo"
+"bgp"
+"bgq"
+"bgr"
+"bgs"
+"bgt"
+"bgu"
+"bgv"
+"bgw"
+"bgx"
+"bgy"
+"bgz"
+"bha"
+"bhb"
+"bhc"
+"bhd"
+"bhe"
+"bhf"
+"bhg"
+"bhh"
+"bhi"
+"bhj"
+"bhk"
+"bhl"
+"bhm"
+"bhn"
+"bho"
+"bhp"
+"bhq"
+"bhr"
+"bhs"
+"bht"
+"bhu"
+"bhv"
+"bhw"
+"bhx"
+"bhy"
+"bhz"
+"bia"
+"bib"
+"bic"
+"bid"
+"bie"
+"bif"
+"big"
+"bij"
+"bik"
+"bil"
+"bim"
+"bin"
+"bio"
+"bip"
+"biq"
+"bir"
+"bit"
+"biu"
+"biv"
+"biw"
+"bix"
+"biy"
+"biz"
+"bja"
+"bjb"
+"bjc"
+"bjd"
+"bje"
+"bjf"
+"bjg"
+"bjh"
+"bji"
+"bjj"
+"bjk"
+"bjl"
+"bjm"
+"bjn"
+"bjo"
+"bjq"
+"bjr"
+"bjs"
+"bjt"
+"bju"
+"bjv"
+"bjw"
+"bjx"
+"bjy"
+"bjz"
+"bka"
+"bkb"
+"bkc"
+"bkd"
+"bkf"
+"bkg"
+"bkh"
+"bki"
+"bkj"
+"bkk"
+"bkl"
+"bkm"
+"bkn"
+"bko"
+"bkp"
+"bkq"
+"bkr"
+"bks"
+"bkt"
+"bku"
+"bkv"
+"bkw"
+"bkx"
+"bky"
+"bkz"
+"bla"
+"blb"
+"blc"
+"bld"
+"ble"
+"blf"
+"blg"
+"blh"
+"bli"
+"blj"
+"blk"
+"bll"
+"blm"
+"bln"
+"blo"
+"blp"
+"blq"
+"blr"
+"bls"
+"blt"
+"blv"
+"blw"
+"blx"
+"bly"
+"blz"
+"bma"
+"bmb"
+"bmc"
+"bmd"
+"bme"
+"bmf"
+"bmg"
+"bmh"
+"bmi"
+"bmj"
+"bmk"
+"bml"
+"bmm"
+"bmn"
+"bmo"
+"bmp"
+"bmq"
+"bmr"
+"bms"
+"bmt"
+"bmu"
+"bmv"
+"bmw"
+"bmx"
+"bmy"
+"bmz"
+"bna"
+"bnb"
+"bnc"
+"bnd"
+"bne"
+"bnf"
+"bng"
+"bni"
+"bnj"
+"bnk"
+"bnl"
+"bnm"
+"bnn"
+"bno"
+"bnp"
+"bnq"
+"bnr"
+"bns"
+"bnt"
+"bnu"
+"bnv"
+"bnw"
+"bnx"
+"bny"
+"bnz"
+"boa"
+"bob"
+"boe"
+"bof"
+"bog"
+"boh"
+"boi"
+"boj"
+"bok"
+"bol"
+"bom"
+"bon"
+"boo"
+"bop"
+"boq"
+"bor"
+"bot"
+"bou"
+"bov"
+"bow"
+"box"
+"boy"
+"boz"
+"bpa"
+"bpb"
+"bpd"
+"bpg"
+"bph"
+"bpi"
+"bpj"
+"bpk"
+"bpl"
+"bpm"
+"bpn"
+"bpo"
+"bpp"
+"bpq"
+"bpr"
+"bps"
+"bpt"
+"bpu"
+"bpv"
+"bpw"
+"bpx"
+"bpy"
+"bpz"
+"bqa"
+"bqb"
+"bqc"
+"bqd"
+"bqf"
+"bqg"
+"bqh"
+"bqi"
+"bqj"
+"bqk"
+"bql"
+"bqm"
+"bqn"
+"bqo"
+"bqp"
+"bqq"
+"bqr"
+"bqs"
+"bqt"
+"bqu"
+"bqv"
+"bqw"
+"bqx"
+"bqy"
+"bqz"
+"bra"
+"brb"
+"brc"
+"brd"
+"brf"
+"brg"
+"brh"
+"bri"
+"brj"
+"brk"
+"brl"
+"brm"
+"brn"
+"bro"
+"brp"
+"brq"
+"brr"
+"brs"
+"brt"
+"bru"
+"brv"
+"brw"
+"brx"
+"bry"
+"brz"
+"bsa"
+"bsb"
+"bsc"
+"bse"
+"bsf"
+"bsg"
+"bsh"
+"bsi"
+"bsj"
+"bsk"
+"bsl"
+"bsm"
+"bsn"
+"bso"
+"bsp"
+"bsq"
+"bsr"
+"bss"
+"bst"
+"bsu"
+"bsv"
+"bsw"
+"bsx"
+"bsy"
+"bta"
+"btb"
+"btc"
+"btd"
+"bte"
+"btf"
+"btg"
+"bth"
+"bti"
+"btj"
+"btk"
+"btl"
+"btm"
+"btn"
+"bto"
+"btp"
+"btq"
+"btr"
+"bts"
+"btt"
+"btu"
+"btv"
+"btw"
+"btx"
+"bty"
+"btz"
+"bua"
+"bub"
+"buc"
+"bud"
+"bue"
+"buf"
+"bug"
+"buh"
+"bui"
+"buj"
+"buk"
+"bum"
+"bun"
+"buo"
+"bup"
+"buq"
+"bus"
+"but"
+"buu"
+"buv"
+"buw"
+"bux"
+"buy"
+"buz"
+"bva"
+"bvb"
+"bvc"
+"bvd"
+"bve"
+"bvf"
+"bvg"
+"bvh"
+"bvi"
+"bvj"
+"bvk"
+"bvl"
+"bvm"
+"bvn"
+"bvo"
+"bvq"
+"bvr"
+"bvt"
+"bvu"
+"bvv"
+"bvw"
+"bvx"
+"bvy"
+"bvz"
+"bwa"
+"bwb"
+"bwc"
+"bwd"
+"bwe"
+"bwf"
+"bwg"
+"bwh"
+"bwi"
+"bwj"
+"bwk"
+"bwl"
+"bwm"
+"bwn"
+"bwo"
+"bwp"
+"bwq"
+"bwr"
+"bws"
+"bwt"
+"bwu"
+"bww"
+"bwx"
+"bwy"
+"bwz"
+"bxa"
+"bxb"
+"bxc"
+"bxd"
+"bxe"
+"bxf"
+"bxg"
+"bxh"
+"bxi"
+"bxj"
+"bxk"
+"bxl"
+"bxm"
+"bxn"
+"bxo"
+"bxp"
+"bxq"
+"bxr"
+"bxs"
+"bxu"
+"bxv"
+"bxw"
+"bxx"
+"bxz"
+"bya"
+"byb"
+"byc"
+"byd"
+"bye"
+"byf"
+"byg"
+"byh"
+"byi"
+"byj"
+"byk"
+"byl"
+"bym"
+"byn"
+"byo"
+"byp"
+"byq"
+"byr"
+"bys"
+"byt"
+"byv"
+"byw"
+"byx"
+"byy"
+"byz"
+"bza"
+"bzb"
+"bzd"
+"bze"
+"bzf"
+"bzg"
+"bzh"
+"bzi"
+"bzj"
+"bzk"
+"bzl"
+"bzm"
+"bzn"
+"bzo"
+"bzp"
+"bzq"
+"bzr"
+"bzs"
+"bzt"
+"bzu"
+"bzv"
+"bzw"
+"bzx"
+"bzy"
+"bzz"
+"caa"
+"cab"
+"cac"
+"cad"
+"cae"
+"caf"
+"cag"
+"cah"
+"cai"
+"caj"
+"cak"
+"cal"
+"cam"
+"can"
+"cao"
+"cap"
+"caq"
+"car"
+"cas"
+"cau"
+"cav"
+"caw"
+"cax"
+"cay"
+"caz"
+"cba"
+"cbb"
+"cbc"
+"cbd"
+"cbe"
+"cbg"
+"cbh"
+"cbi"
+"cbj"
+"cbk"
+"cbl"
+"cbn"
+"cbo"
+"cbr"
+"cbs"
+"cbt"
+"cbu"
+"cbv"
+"cbw"
+"cby"
+"cca"
+"ccc"
+"ccd"
+"cce"
+"ccg"
+"cch"
+"ccj"
+"ccl"
+"ccm"
+"ccn"
+"cco"
+"ccp"
+"ccq"
+"ccr"
+"ccs"
+"cda"
+"cdc"
+"cdd"
+"cde"
+"cdf"
+"cdg"
+"cdh"
+"cdi"
+"cdj"
+"cdm"
+"cdn"
+"cdo"
+"cdr"
+"cds"
+"cdy"
+"cdz"
+"cea"
+"ceb"
+"ceg"
+"cel"
+"cen"
+"cet"
+"cfa"
+"cfd"
+"cfg"
+"cfm"
+"cga"
+"cgc"
+"cgg"
+"cgk"
+"chb"
+"chc"
+"chd"
+"chf"
+"chg"
+"chh"
+"chj"
+"chk"
+"chl"
+"chm"
+"chn"
+"cho"
+"chp"
+"chq"
+"chr"
+"cht"
+"chw"
+"chx"
+"chy"
+"chz"
+"cia"
+"cib"
+"cic"
+"cid"
+"cie"
+"cih"
+"cik"
+"cim"
+"cin"
+"cip"
+"cir"
+"ciw"
+"ciy"
+"cja"
+"cje"
+"cjh"
+"cji"
+"cjk"
+"cjm"
+"cjn"
+"cjo"
+"cjp"
+"cjr"
+"cjs"
+"cjv"
+"cjy"
+"cka"
+"ckb"
+"ckh"
+"ckl"
+"cko"
+"ckq"
+"ckr"
+"cks"
+"ckt"
+"cku"
+"ckv"
+"ckx"
+"cky"
+"ckz"
+"cla"
+"clc"
+"cld"
+"cle"
+"clh"
+"cli"
+"clk"
+"cll"
+"clm"
+"clo"
+"clu"
+"clw"
+"cly"
+"cma"
+"cmc"
+"cme"
+"cmg"
+"cmi"
+"cmk"
+"cml"
+"cmm"
+"cmn"
+"cmo"
+"cmr"
+"cms"
+"cmt"
+"cna"
+"cnb"
+"cnc"
+"cng"
+"cnh"
+"cni"
+"cnk"
+"cnl"
+"cno"
+"cns"
+"cnt"
+"cnu"
+"cnw"
+"cnx"
+"coa"
+"cob"
+"coc"
+"cod"
+"coe"
+"cof"
+"cog"
+"coh"
+"coj"
+"cok"
+"col"
+"com"
+"con"
+"coo"
+"cop"
+"coq"
+"cot"
+"cou"
+"cov"
+"cow"
+"cox"
+"coy"
+"coz"
+"cpa"
+"cpb"
+"cpc"
+"cpe"
+"cpf"
+"cpg"
+"cpi"
+"cpn"
+"cpp"
+"cps"
+"cpu"
+"cpx"
+"cpy"
+"cqd"
+"cqu"
+"cra"
+"crb"
+"crc"
+"crd"
+"crf"
+"crg"
+"crh"
+"cri"
+"crj"
+"crk"
+"crl"
+"crm"
+"crn"
+"cro"
+"crp"
+"crq"
+"crr"
+"crs"
+"crt"
+"crv"
+"crw"
+"crx"
+"cry"
+"crz"
+"csa"
+"csb"
+"csc"
+"csd"
+"cse"
+"csf"
+"csg"
+"csh"
+"csi"
+"csk"
+"csl"
+"csm"
+"csn"
+"cso"
+"csq"
+"csr"
+"css"
+"cst"
+"csu"
+"csw"
+"csy"
+"csz"
+"cta"
+"ctc"
+"ctd"
+"cte"
+"ctg"
+"ctl"
+"ctm"
+"ctn"
+"cto"
+"ctp"
+"cts"
+"ctt"
+"ctu"
+"ctz"
+"cua"
+"cub"
+"cuc"
+"cug"
+"cuh"
+"cui"
+"cuj"
+"cuk"
+"cul"
+"cum"
+"cuo"
+"cup"
+"cuq"
+"cur"
+"cus"
+"cut"
+"cuu"
+"cuv"
+"cuw"
+"cux"
+"cvg"
+"cvn"
+"cwa"
+"cwb"
+"cwd"
+"cwe"
+"cwg"
+"cwt"
+"cya"
+"cyb"
+"cyo"
+"czh"
+"czk"
+"czn"
+"czo"
+"czt"
+"daa"
+"dac"
+"dad"
+"dae"
+"daf"
+"dag"
+"dah"
+"dai"
+"daj"
+"dak"
+"dal"
+"dam"
+"dao"
+"dap"
+"daq"
+"dar"
+"das"
+"dau"
+"dav"
+"daw"
+"dax"
+"day"
+"daz"
+"dba"
+"dbb"
+"dbd"
+"dbe"
+"dbf"
+"dbg"
+"dbi"
+"dbj"
+"dbl"
+"dbm"
+"dbn"
+"dbo"
+"dbp"
+"dbq"
+"dbr"
+"dbu"
+"dbv"
+"dby"
+"dcc"
+"dcr"
+"ddd"
+"dde"
+"ddg"
+"ddi"
+"ddj"
+"ddn"
+"ddo"
+"dds"
+"ddw"
+"dec"
+"ded"
+"dee"
+"def"
+"deg"
+"deh"
+"dei"
+"dek"
+"del"
+"dem"
+"den"
+"dep"
+"deq"
+"der"
+"des"
+"dev"
+"dez"
+"dga"
+"dgb"
+"dgc"
+"dgd"
+"dge"
+"dgg"
+"dgh"
+"dgi"
+"dgk"
+"dgn"