From 87d133428087e2a7db022a0093e04682e4a994ed Mon Sep 17 00:00:00 2001 From: Harvey Kandola Date: Wed, 30 Nov 2016 17:56:36 -0800 Subject: [PATCH] rollback page revisions --- README.md | 2 +- .../components/document/document-history.js | 55 + app/app/components/ui/ui-avatar.js | 20 + app/app/models/page.js | 5 + app/app/pods/document/history/controller.js | 28 + app/app/pods/document/history/route.js | 18 + app/app/pods/document/history/template.hbs | 2 + app/app/router.js | 3 + app/app/services/document.js | 12 + app/app/styles/view/document/all.scss | 1 + app/app/styles/view/document/history.scss | 72 + app/app/styles/view/document/toolbar.scss | 22 + .../components/document/document-history.hbs | 40 + .../components/document/document-toolbar.hbs | 5 + app/app/templates/components/ui/ui-avatar.hbs | 3 + app/package.json | 2 +- core/api/endpoint/page_endpoint.go | 230 ++ core/api/endpoint/router.go | 5 + core/api/entity/objects.go | 21 + core/api/request/page.go | 99 +- core/product.go | 4 +- .../github.com/documize/html-diff/.gitignore | 30 + vendor/github.com/documize/html-diff/LICENSE | 21 + .../github.com/documize/html-diff/README.md | 27 + .../github.com/documize/html-diff/append.go | 221 ++ .../documize/html-diff/benchmark_test.go | 28 + vendor/github.com/documize/html-diff/clean.go | 67 + .../documize/html-diff/datafor_test.go | 1520 ++++++++++ .../documize/html-diff/example_test.go | 29 + .../documize/html-diff/example_test.html | 45 + .../documize/html-diff/example_test.png | Bin 0 -> 47685 bytes vendor/github.com/documize/html-diff/fuzz.go | 212 ++ .../github.com/documize/html-diff/htmldiff.go | 193 ++ .../documize/html-diff/htmldiff_test.go | 369 +++ vendor/github.com/documize/html-diff/nodes.go | 68 + vendor/github.com/documize/html-diff/pos.go | 47 + .../documize/html-diff/testin/bbc.html | 2589 +++++++++++++++++ .../documize/html-diff/testin/bing.html | 57 + .../documize/html-diff/testin/google.html | 1261 ++++++++ .../documize/html-diff/testin/reuters.html | 1749 +++++++++++ .../documize/html-diff/treerunes.go | 124 + .../vendor/github.com/mb0/diff/LICENSE | 22 + .../vendor/github.com/mb0/diff/README.md | 34 + .../vendor/github.com/mb0/diff/diff.go | 222 ++ .../vendor/github.com/mb0/diff/diff_test.go | 239 ++ .../github.com/mb0/diff/example_test.go | 57 + .../vendor/golang.org/x/net/html/atom/atom.go | 78 + .../golang.org/x/net/html/atom/atom_test.go | 109 + .../vendor/golang.org/x/net/html/atom/gen.go | 648 +++++ .../golang.org/x/net/html/atom/table.go | 713 +++++ .../golang.org/x/net/html/atom/table_test.go | 351 +++ .../golang.org/x/net/html/charset/charset.go | 257 ++ .../x/net/html/charset/charset_test.go | 237 ++ .../html/charset/testdata/HTTP-charset.html | 48 + .../charset/testdata/HTTP-vs-UTF-8-BOM.html | 48 + .../testdata/HTTP-vs-meta-charset.html | 49 + .../testdata/HTTP-vs-meta-content.html | 49 + .../testdata/No-encoding-declaration.html | 47 + .../x/net/html/charset/testdata/README | 9 + .../html/charset/testdata/UTF-16BE-BOM.html | Bin 0 -> 2670 bytes .../html/charset/testdata/UTF-16LE-BOM.html | Bin 0 -> 2682 bytes .../testdata/UTF-8-BOM-vs-meta-charset.html | 49 + .../testdata/UTF-8-BOM-vs-meta-content.html | 48 + .../testdata/meta-charset-attribute.html | 48 + .../testdata/meta-content-attribute.html | 48 + .../vendor/golang.org/x/net/html/const.go | 102 + .../vendor/golang.org/x/net/html/doc.go | 106 + .../vendor/golang.org/x/net/html/doctype.go | 156 + .../vendor/golang.org/x/net/html/entity.go | 2253 ++++++++++++++ .../golang.org/x/net/html/entity_test.go | 29 + .../vendor/golang.org/x/net/html/escape.go | 258 ++ .../golang.org/x/net/html/escape_test.go | 97 + .../golang.org/x/net/html/example_test.go | 40 + .../vendor/golang.org/x/net/html/foreign.go | 226 ++ .../vendor/golang.org/x/net/html/node.go | 193 ++ .../vendor/golang.org/x/net/html/node_test.go | 146 + .../vendor/golang.org/x/net/html/parse.go | 2094 +++++++++++++ .../golang.org/x/net/html/parse_test.go | 388 +++ .../vendor/golang.org/x/net/html/render.go | 271 ++ .../golang.org/x/net/html/render_test.go | 156 + .../golang.org/x/net/html/testdata/go1.html | 2237 ++++++++++++++ .../x/net/html/testdata/webkit/README | 28 + .../x/net/html/testdata/webkit/adoption01.dat | 194 ++ .../x/net/html/testdata/webkit/adoption02.dat | 31 + .../x/net/html/testdata/webkit/comments01.dat | 135 + .../x/net/html/testdata/webkit/doctype01.dat | 370 +++ .../x/net/html/testdata/webkit/entities01.dat | 603 ++++ .../x/net/html/testdata/webkit/entities02.dat | 249 ++ .../html/testdata/webkit/html5test-com.dat | 246 ++ .../x/net/html/testdata/webkit/inbody01.dat | 43 + .../x/net/html/testdata/webkit/isindex.dat | 40 + ...pending-spec-changes-plain-text-unsafe.dat | Bin 0 -> 115 bytes .../testdata/webkit/pending-spec-changes.dat | 52 + .../testdata/webkit/plain-text-unsafe.dat | Bin 0 -> 4166 bytes .../net/html/testdata/webkit/scriptdata01.dat | 308 ++ .../testdata/webkit/scripted/adoption01.dat | 15 + .../testdata/webkit/scripted/webkit01.dat | 28 + .../x/net/html/testdata/webkit/tables01.dat | 212 ++ .../x/net/html/testdata/webkit/tests1.dat | 1952 +++++++++++++ .../x/net/html/testdata/webkit/tests10.dat | 799 +++++ .../x/net/html/testdata/webkit/tests11.dat | 482 +++ .../x/net/html/testdata/webkit/tests12.dat | 62 + .../x/net/html/testdata/webkit/tests14.dat | 74 + .../x/net/html/testdata/webkit/tests15.dat | 208 ++ .../x/net/html/testdata/webkit/tests16.dat | 2299 +++++++++++++++ .../x/net/html/testdata/webkit/tests17.dat | 153 + .../x/net/html/testdata/webkit/tests18.dat | 269 ++ .../x/net/html/testdata/webkit/tests19.dat | 1237 ++++++++ .../x/net/html/testdata/webkit/tests2.dat | 763 +++++ .../x/net/html/testdata/webkit/tests20.dat | 455 +++ .../x/net/html/testdata/webkit/tests21.dat | 221 ++ .../x/net/html/testdata/webkit/tests22.dat | 157 + .../x/net/html/testdata/webkit/tests23.dat | 155 + .../x/net/html/testdata/webkit/tests24.dat | 79 + .../x/net/html/testdata/webkit/tests25.dat | 219 ++ .../x/net/html/testdata/webkit/tests26.dat | 313 ++ .../x/net/html/testdata/webkit/tests3.dat | 305 ++ .../x/net/html/testdata/webkit/tests4.dat | 59 + .../x/net/html/testdata/webkit/tests5.dat | 191 ++ .../x/net/html/testdata/webkit/tests6.dat | 663 +++++ .../x/net/html/testdata/webkit/tests7.dat | 390 +++ .../x/net/html/testdata/webkit/tests8.dat | 148 + .../x/net/html/testdata/webkit/tests9.dat | 457 +++ .../testdata/webkit/tests_innerHTML_1.dat | 741 +++++ .../x/net/html/testdata/webkit/tricky01.dat | 261 ++ .../x/net/html/testdata/webkit/webkit01.dat | 610 ++++ .../x/net/html/testdata/webkit/webkit02.dat | 159 + .../vendor/golang.org/x/net/html/token.go | 1219 ++++++++ .../golang.org/x/net/html/token_test.go | 748 +++++ .../documize/html-diff/vizhtml/viztree.go | 63 + 130 files changed, 39899 insertions(+), 34 deletions(-) create mode 100644 app/app/components/document/document-history.js create mode 100644 app/app/components/ui/ui-avatar.js create mode 100644 app/app/pods/document/history/controller.js create mode 100644 app/app/pods/document/history/route.js create mode 100644 app/app/pods/document/history/template.hbs create mode 100644 app/app/styles/view/document/history.scss create mode 100644 app/app/templates/components/document/document-history.hbs create mode 100644 app/app/templates/components/ui/ui-avatar.hbs create mode 100644 vendor/github.com/documize/html-diff/.gitignore create mode 100644 vendor/github.com/documize/html-diff/LICENSE create mode 100644 vendor/github.com/documize/html-diff/README.md create mode 100644 vendor/github.com/documize/html-diff/append.go create mode 100644 vendor/github.com/documize/html-diff/benchmark_test.go create mode 100644 vendor/github.com/documize/html-diff/clean.go create mode 100644 vendor/github.com/documize/html-diff/datafor_test.go create mode 100644 vendor/github.com/documize/html-diff/example_test.go create mode 100644 vendor/github.com/documize/html-diff/example_test.html create mode 100644 vendor/github.com/documize/html-diff/example_test.png create mode 100644 vendor/github.com/documize/html-diff/fuzz.go create mode 100644 vendor/github.com/documize/html-diff/htmldiff.go create mode 100644 vendor/github.com/documize/html-diff/htmldiff_test.go create mode 100644 vendor/github.com/documize/html-diff/nodes.go create mode 100644 vendor/github.com/documize/html-diff/pos.go create mode 100644 vendor/github.com/documize/html-diff/testin/bbc.html create mode 100644 vendor/github.com/documize/html-diff/testin/bing.html create mode 100644 vendor/github.com/documize/html-diff/testin/google.html create mode 100644 vendor/github.com/documize/html-diff/testin/reuters.html create mode 100644 vendor/github.com/documize/html-diff/treerunes.go create mode 100644 vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/LICENSE create mode 100644 vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/README.md create mode 100644 vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff.go create mode 100644 vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/example_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/gen.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/README create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-content-attribute.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/const.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doc.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doctype.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/example_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/foreign.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/parse.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/parse_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/render.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/render_test.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/go1.html create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/README create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/adoption01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/adoption02.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/comments01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/doctype01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/entities01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/entities02.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/html5test-com.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/inbody01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/isindex.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/pending-spec-changes.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/plain-text-unsafe.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/scriptdata01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/scripted/adoption01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/scripted/webkit01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tables01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests1.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests10.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests11.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests12.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests14.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests15.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests16.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests17.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests18.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests19.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests2.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests20.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests21.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests22.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests23.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests24.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests25.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests26.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests3.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests4.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests5.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests6.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests7.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests8.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests9.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests_innerHTML_1.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tricky01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/webkit01.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/webkit02.dat create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/token.go create mode 100644 vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/token_test.go create mode 100644 vendor/github.com/documize/html-diff/vizhtml/viztree.go diff --git a/README.md b/README.md index d9a11871..6208ee3c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The mission is to bring software dev inspired features (refactoring, testing, li ## Latest version -v0.34.1 +v0.35.0 ## OS Support diff --git a/app/app/components/document/document-history.js b/app/app/components/document/document-history.js new file mode 100644 index 00000000..fc937c98 --- /dev/null +++ b/app/app/components/document/document-history.js @@ -0,0 +1,55 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +import Ember from 'ember'; + +export default Ember.Component.extend({ + revision: {}, + hasDiff: Ember.computed('diff', function () { + return this.get('diff').length > 0; + }), + + didReceiveAttrs() { + let revisions = this.get('revisions'); + + revisions.forEach((revision) => { + Ember.set(revision, 'deleted', revision.revisions === 0); + }); + + this.set('revisions', revisions); + }, + + didInsertElement() { + this._super(...arguments); + + this.eventBus.subscribe('resized', this, 'sizeSidebar'); + this.sizeSidebar(); + }, + + sizeSidebar() { + let size = $(window).height() - 200; + this.$('.document-history > .sidebar').css('height', size + "px"); + }, + + actions: { + getDiff(revision) { + this.set('revision', revision); + if (!revision.deleted) { + this.attrs.onFetchDiff(revision.pageId, revision.id); + } + }, + + rollback() { + let revision = this.get('revision'); + this.attrs.onRollback(revision.pageId, revision.id); + } + } +}); diff --git a/app/app/components/ui/ui-avatar.js b/app/app/components/ui/ui-avatar.js new file mode 100644 index 00000000..c27123fc --- /dev/null +++ b/app/app/components/ui/ui-avatar.js @@ -0,0 +1,20 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +import Ember from 'ember'; +import TooltipMixin from '../../mixins/tooltip'; + +export default Ember.Component.extend(TooltipMixin, { + didRender() { + let refId = this.get('refId'); + this.addTooltip(document.getElementById(`avatar-${refId}`)); + }, +}); diff --git a/app/app/models/page.js b/app/app/models/page.js index a4e88fac..d72ca489 100644 --- a/app/app/models/page.js +++ b/app/app/models/page.js @@ -39,6 +39,11 @@ export default Model.extend({ let tocIndent = this.get('tocIndent'); return `margin-left-${tocIndent}`; }), + + hasRevisions: Ember.computed('revisions', function () { + return this.get('revisions') > 0; + }), + created: attr(), revised: attr() }); diff --git a/app/app/pods/document/history/controller.js b/app/app/pods/document/history/controller.js new file mode 100644 index 00000000..c7cd7d3b --- /dev/null +++ b/app/app/pods/document/history/controller.js @@ -0,0 +1,28 @@ +import Ember from 'ember'; +import NotifierMixin from '../../../mixins/notifier'; + +export default Ember.Controller.extend(NotifierMixin, { + documentService: Ember.inject.service('document'), + + actions: { + onFetchDiff(pageId, revisionId) { + this.audit.record("compared-diff"); + + this.get('documentService').getPageRevisionDiff(this.get('model.document.id'), pageId, revisionId).then((revision) => { + this.set('model.diff', revision); + }); + }, + + onRollback(pageId, revisionId) { + this.audit.record("restored-page"); + + this.get('documentService').rollbackPage(this.get('model.document.id'), pageId, revisionId).then(() => { + this.transitionToRoute('document', { + queryParams: { + page: pageId + } + }); + }); + } + } +}); diff --git a/app/app/pods/document/history/route.js b/app/app/pods/document/history/route.js new file mode 100644 index 00000000..a1ffe5fe --- /dev/null +++ b/app/app/pods/document/history/route.js @@ -0,0 +1,18 @@ +import Ember from 'ember'; +import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; + +export default Ember.Route.extend(AuthenticatedRouteMixin, { + documentService: Ember.inject.service('document'), + folderService: Ember.inject.service('folder'), + + model() { + return Ember.RSVP.hash({ + folders: this.modelFor('document').folders, + folder: this.modelFor('document').folder, + document: this.modelFor('document').document, + pages: this.modelFor('document').pages, + diff: "", + revisions: this.get('documentService').getDocumentRevisions(this.modelFor('document').document.get('id')) + }); + } +}); diff --git a/app/app/pods/document/history/template.hbs b/app/app/pods/document/history/template.hbs new file mode 100644 index 00000000..ac397cf6 --- /dev/null +++ b/app/app/pods/document/history/template.hbs @@ -0,0 +1,2 @@ +{{document/document-history document=model.document folder=model.folder pages=model.pages revisions=model.revisions diff=model.diff + onFetchDiff=(action 'onFetchDiff') onRollback=(action 'onRollback')}} diff --git a/app/app/router.js b/app/app/router.js index 2b756e84..421b0ec4 100644 --- a/app/app/router.js +++ b/app/app/router.js @@ -47,6 +47,9 @@ export default Router.map(function () { this.route('wizard', { path: 'add' }); + this.route('history', { + path: 'history' + }); }); this.route('customize', { diff --git a/app/app/services/document.js b/app/app/services/document.js index 53dc4450..8eeb18e8 100644 --- a/app/app/services/document.js +++ b/app/app/services/document.js @@ -170,6 +170,14 @@ export default Ember.Service.extend({ }); }, + getDocumentRevisions(documentId) { + let url = `documents/${documentId}/revisions`; + + return this.get('ajax').request(url, { + method: "GET" + }); + }, + getPageRevisions(documentId, pageId) { let url = `documents/${documentId}/pages/${pageId}/revisions`; @@ -184,6 +192,10 @@ export default Ember.Service.extend({ return this.get('ajax').request(url, { method: "GET", dataType: 'text' + }).then((response) => { + return response; + }).catch((error) => { + return ""; }); }, diff --git a/app/app/styles/view/document/all.scss b/app/app/styles/view/document/all.scss index 3274d65d..a7c42597 100644 --- a/app/app/styles/view/document/all.scss +++ b/app/app/styles/view/document/all.scss @@ -3,6 +3,7 @@ @import "edit-tools.scss"; @import "editor.scss"; @import "files.scss"; +@import "history.scss"; @import "sidebar.scss"; @import "toolbar.scss"; @import "wizard.scss"; diff --git a/app/app/styles/view/document/history.scss b/app/app/styles/view/document/history.scss new file mode 100644 index 00000000..9a954516 --- /dev/null +++ b/app/app/styles/view/document/history.scss @@ -0,0 +1,72 @@ +.document-history { + position: relative; + + > .sidebar { + position: relative; + overflow-y: scroll; + + > .heading { + font-size: 1.2rem; + font-family: $font-light; + color: $color-off-black; + } + + > .line { + width: 2px; + background-color: $color-stroke; + height: 100%; + position: absolute; + left: 17px; + z-index: -1; + } + + > .items { + list-style-type: none; + margin: 0; + padding: 20px 0 10px; + white-space: nowrap; + + > .item { + margin: 0; + padding: 10px 0; + width: 100%; + color: $color-off-black; + @include ease-in(); + cursor: pointer; + + > .avatar-box { + display: inline-block; + } + + > .date { + display: inline-block; + font-size: 1rem; + font-family: $font-light; + margin-left: 25px; + } + + > .detail { + display: block; + font-size: 1.2rem; + font-family: $font-semibold; + margin-left: 65px; + overflow: hidden; + text-overflow: ellipsis; + } + + &:hover { + color: $color-link; + } + } + + > .deleted { + color: $color-red; + cursor: not-allowed; + + &:hover { + color: $color-red; + } + } + } + } +} diff --git a/app/app/styles/view/document/toolbar.scss b/app/app/styles/view/document/toolbar.scss index ba360651..61791aec 100644 --- a/app/app/styles/view/document/toolbar.scss +++ b/app/app/styles/view/document/toolbar.scss @@ -88,5 +88,27 @@ color: $color-primary; } } + + > a { + display: inline-block; + + > .option { + list-style-type: none; + display: inline-block; + margin: 0 0 0 20px; + padding: 0; + color: $color-gray; + cursor: pointer; + @include ease-in(); + + &:hover { + color: $color-link; + } + + > .pinned { + color: $color-primary; + } + } + } } } diff --git a/app/app/templates/components/document/document-history.hbs b/app/app/templates/components/document/document-history.hbs new file mode 100644 index 00000000..fce0ade8 --- /dev/null +++ b/app/app/templates/components/document/document-history.hbs @@ -0,0 +1,40 @@ +
+
+ +
+ {{#if hasDiff}} +
+ Restore +
+ {{#dropdown-dialog target="restore-history-button" position="bottom right" button="Restore" color="flat-green" onAction=(action 'rollback')}} +

Are you sure you want to roll back to this version?

+ {{/dropdown-dialog}} +
+
+ {{{diff}}} +
+ {{/if}} +
+ +
+
+ +
+ +
+
diff --git a/app/app/templates/components/document/document-toolbar.hbs b/app/app/templates/components/document/document-toolbar.hbs index db08bb23..698c0cb7 100644 --- a/app/app/templates/components/document/document-toolbar.hbs +++ b/app/app/templates/components/document/document-toolbar.hbs @@ -36,6 +36,11 @@
  • star_border
  • {{/if}} {{/if}} + {{#if session.authenticated}} + {{#link-to 'document.history'}} +
  • history
  • + {{/link-to}} + {{/if}} {{#if isEditor}}
  • content_copy
  • settings
  • diff --git a/app/app/templates/components/ui/ui-avatar.hbs b/app/app/templates/components/ui/ui-avatar.hbs new file mode 100644 index 00000000..136fd2bb --- /dev/null +++ b/app/app/templates/components/ui/ui-avatar.hbs @@ -0,0 +1,3 @@ +
    + {{user-initials firstname lastname}} +
    diff --git a/app/package.json b/app/package.json index cb97c8fe..16006fad 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "documize", - "version": "0.34.1", + "version": "0.35.0", "description": "The Document IDE", "private": true, "directories": { diff --git a/core/api/endpoint/page_endpoint.go b/core/api/endpoint/page_endpoint.go index a22532bd..0095e3d6 100644 --- a/core/api/endpoint/page_endpoint.go +++ b/core/api/endpoint/page_endpoint.go @@ -26,6 +26,7 @@ import ( "github.com/documize/community/core/log" "github.com/documize/community/core/section/provider" "github.com/documize/community/core/utility" + htmldiff "github.com/documize/html-diff" "github.com/gorilla/mux" ) @@ -645,3 +646,232 @@ func GetDocumentPageMeta(w http.ResponseWriter, r *http.Request) { writeSuccessBytes(w, json) } + +/******************** +* Page Revisions +********************/ + +// GetDocumentRevisions returns all changes for a document. +func GetDocumentRevisions(w http.ResponseWriter, r *http.Request) { + method := "GetDocumentPageRevisions" + p := request.GetPersister(r) + + params := mux.Vars(r) + documentID := params["documentID"] + + if len(documentID) == 0 { + writeMissingDataError(w, method, "documentID") + return + } + + if !p.CanViewDocument(documentID) { + writeForbiddenError(w) + return + } + + revisions, err := p.GetDocumentRevisions(documentID) + + payload, err := json.Marshal(revisions) + + if err != nil { + writeJSONMarshalError(w, method, "revision", err) + return + } + + writeSuccessBytes(w, payload) +} + +// GetDocumentPageRevisions returns all changes for a given page. +func GetDocumentPageRevisions(w http.ResponseWriter, r *http.Request) { + method := "GetDocumentPageRevisions" + p := request.GetPersister(r) + + params := mux.Vars(r) + documentID := params["documentID"] + + if len(documentID) == 0 { + writeMissingDataError(w, method, "documentID") + return + } + + if !p.CanViewDocument(documentID) { + writeForbiddenError(w) + return + } + + pageID := params["pageID"] + + if len(pageID) == 0 { + writeMissingDataError(w, method, "pageID") + return + } + + revisions, err := p.GetPageRevisions(pageID) + + payload, err := json.Marshal(revisions) + + if err != nil { + writeJSONMarshalError(w, method, "revision", err) + return + } + + writeSuccessBytes(w, payload) +} + +// GetDocumentPageDiff returns HTML diff between two revisions of a given page. +func GetDocumentPageDiff(w http.ResponseWriter, r *http.Request) { + method := "GetDocumentPageDiff" + p := request.GetPersister(r) + + params := mux.Vars(r) + documentID := params["documentID"] + + if len(documentID) == 0 { + writeMissingDataError(w, method, "documentID") + return + } + + if !p.CanViewDocument(documentID) { + writeForbiddenError(w) + return + } + + pageID := params["pageID"] + + if len(pageID) == 0 { + writeMissingDataError(w, method, "pageID") + return + } + + revisionID := params["revisionID"] + + if len(revisionID) == 0 { + writeMissingDataError(w, method, "revisionID") + return + } + + page, err := p.GetPage(pageID) + + if err == sql.ErrNoRows { + writeNotFoundError(w, method, revisionID) + return + } + + revision, err := p.GetPageRevision(revisionID) + + latestHTML := page.Body + previousHTML := revision.Body + var result []byte + + var cfg = &htmldiff.Config{ + Granularity: 5, + InsertedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: palegreen;"}}, + DeletedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightpink; text-decoration: line-through;"}}, + ReplacedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightskyblue;"}}, + CleanTags: []string{"documize"}, + } + res, err := cfg.HTMLdiff([]string{latestHTML, previousHTML}) + if err != nil { + writeServerError(w, method, err) + return + } + + result = []byte(res[0]) + + _, err = w.Write(result) + log.IfErr(err) +} + +// RollbackDocumentPage rolls-back to a specific page revision. +func RollbackDocumentPage(w http.ResponseWriter, r *http.Request) { + method := "RollbackDocumentPage" + p := request.GetPersister(r) + + params := mux.Vars(r) + documentID := params["documentID"] + + if len(documentID) == 0 { + writeMissingDataError(w, method, "documentID") + return + } + + pageID := params["pageID"] + + if len(pageID) == 0 { + writeMissingDataError(w, method, "pageID") + return + } + + revisionID := params["revisionID"] + + if len(revisionID) == 0 { + writeMissingDataError(w, method, "revisionID") + return + } + + if !p.CanChangeDocument(documentID) { + writeForbiddenError(w) + return + } + + tx, err := request.Db.Beginx() + if err != nil { + writeTransactionError(w, method, err) + return + } + + p.Context.Transaction = tx + + // fetch page + page, err := p.GetPage(pageID) + if err != nil { + writeGeneralSQLError(w, method, err) + return + } + + // fetch page meta + meta, err := p.GetPageMeta(pageID) + if err != nil { + writeGeneralSQLError(w, method, err) + return + } + + // fetch revision + revision, err := p.GetPageRevision(revisionID) + if err != nil { + writeGeneralSQLError(w, method, err) + return + } + + // roll back page + page.Body = revision.Body + refID := util.UniqueID() + + err = p.UpdatePage(page, refID, p.Context.UserID, false) + if err != nil { + log.IfErr(tx.Rollback()) + writeGeneralSQLError(w, method, err) + return + } + + // roll back page meta + meta.Config = revision.Config + meta.RawBody = revision.RawBody + + err = p.UpdatePageMeta(meta, false) + if err != nil { + log.IfErr(tx.Rollback()) + writeGeneralSQLError(w, method, err) + return + } + + log.IfErr(tx.Commit()) + + payload, err := json.Marshal(page) + if err != nil { + writeJSONMarshalError(w, method, "revision", err) + return + } + + writeSuccessBytes(w, payload) +} diff --git a/core/api/endpoint/router.go b/core/api/endpoint/router.go index a92cd01e..3e9953e2 100644 --- a/core/api/endpoint/router.go +++ b/core/api/endpoint/router.go @@ -159,6 +159,11 @@ func init() { log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/level", []string{"POST", "OPTIONS"}, nil, ChangeDocumentPageLevel)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/sequence", []string{"POST", "OPTIONS"}, nil, ChangeDocumentPageSequence)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/batch", []string{"POST", "OPTIONS"}, nil, GetDocumentPagesBatch)) + log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}/revisions", []string{"GET", "OPTIONS"}, nil, GetDocumentPageRevisions)) + log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}/revisions/{revisionID}", []string{"GET", "OPTIONS"}, nil, GetDocumentPageDiff)) + log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}/revisions/{revisionID}", []string{"POST", "OPTIONS"}, nil, RollbackDocumentPage)) + log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/revisions", []string{"GET", "OPTIONS"}, nil, GetDocumentRevisions)) + log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages", []string{"GET", "OPTIONS"}, nil, GetDocumentPages)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}", []string{"PUT", "OPTIONS"}, nil, UpdateDocumentPage)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}", []string{"DELETE", "OPTIONS"}, nil, DeleteDocumentPage)) diff --git a/core/api/entity/objects.go b/core/api/entity/objects.go index b1827e6b..e2a4c6a5 100644 --- a/core/api/entity/objects.go +++ b/core/api/entity/objects.go @@ -238,6 +238,27 @@ func (p *PageMeta) SetDefaults() { } } +// Revision holds the previous version of a Page. +type Revision struct { + BaseEntity + OrgID string `json:"orgId"` + DocumentID string `json:"documentId"` + PageID string `json:"pageId"` + OwnerID string `json:"ownerId"` + UserID string `json:"userId"` + ContentType string `json:"contentType"` + PageType string `json:"pageType"` + Title string `json:"title"` + Body string `json:"body"` + RawBody string `json:"rawBody"` + Config string `json:"config"` + Email string `json:"email"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` + Initials string `json:"initials"` + Revisions int `json:"revisions"` +} + // DocumentMeta details who viewed the document. type DocumentMeta struct { Viewers []DocumentMetaViewer `json:"viewers"` diff --git a/core/api/request/page.go b/core/api/request/page.go index 652ca4fa..8674deed 100644 --- a/core/api/request/page.go +++ b/core/api/request/page.go @@ -258,36 +258,6 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis } } - //if page.Level == 1 { // may need to update the document name - //var doc entity.Document - - //stmt4, err := p.Context.Transaction.Preparex("SELECT id, refid, orgid, labelid, job, location, title, excerpt, slug, tags, template, created, revised FROM document WHERE refid=?") - //defer utility.Close(stmt4) - - //if err != nil { - //log.Error(fmt.Sprintf("Unable to prepare pagemanager doc query for Id %s", page.DocumentID), err) - //return err - //} - - //err = stmt4.Get(&doc, page.DocumentID) - - //if err != nil { - //log.Error(fmt.Sprintf("Unable to execute pagemanager document query for Id %s", page.DocumentID), err) - //return err - //} - - //if doc.Title != page.Title { - //doc.Title = page.Title - //doc.Revised = page.Revised - //err = p.UpdateDocument(doc) - - //if err != nil { - //log.Error(fmt.Sprintf("Unable to update document when page 1 altered DocumentId %s", page.DocumentID), err) - //return err - //} - //} - //} - // find any content links in the HTML links := util.GetContentLinks(page.Body) @@ -336,6 +306,7 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis func (p *Persister) UpdatePageMeta(meta entity.PageMeta, updateUserID bool) (err error) { err = nil meta.Revised = time.Now().UTC() + if updateUserID { meta.UserID = p.Context.UserID } @@ -424,6 +395,9 @@ func (p *Persister) DeletePage(documentID, pageID string) (rows int64, err error // mark as orphan links to this page err = p.MarkOrphanPageLink(pageID) + // nuke revisions + _, err = p.DeletePageRevisions(pageID) + p.Base.Audit(p.Context, "remove-page", documentID, pageID) } @@ -469,3 +443,68 @@ func (p *Persister) GetDocumentPageMeta(documentID string, externalSourceOnly bo return } + +/******************** +* Page Revisions +********************/ + +// GetPageRevision returns the revisionID page revision record. +func (p *Persister) GetPageRevision(revisionID string) (revision entity.Revision, err error) { + stmt, err := Db.Preparex("SELECT id, refid, orgid, documentid, ownerid, pageid, userid, contenttype, pagetype, title, body, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, created, revised FROM revision WHERE orgid=? and refid=?") + defer utility.Close(stmt) + + if err != nil { + log.Error(fmt.Sprintf("Unable to prepare select for revision %s", revisionID), err) + return + } + + err = stmt.Get(&revision, p.Context.OrgID, revisionID) + + if err != nil { + log.Error(fmt.Sprintf("Unable to execute select for revision %s", revisionID), err) + return + } + + return +} + +// GetDocumentRevisions returns a slice of page revision records for a given document, in the order they were created. +// Then audits that the get-page-revisions action has occurred. +func (p *Persister) GetDocumentRevisions(documentID string) (revisions []entity.Revision, err error) { + err = Db.Select(&revisions, "SELECT a.id, a.refid, a.orgid, a.documentid, a.ownerid, a.pageid, a.userid, a.contenttype, a.pagetype, a.title, /*a.body, a.rawbody, a.config,*/ a.created, a.revised, coalesce(b.email,'') as email, coalesce(b.firstname,'') as firstname, coalesce(b.lastname,'') as lastname, coalesce(b.initials,'') as initials, coalesce(p.revisions, 0) as revisions FROM revision a LEFT JOIN user b ON a.userid=b.refid LEFT JOIN page p ON a.pageid=p.refid WHERE a.orgid=? AND a.documentid=? AND a.pagetype='section' ORDER BY a.id DESC", p.Context.OrgID, documentID) + + if err != nil { + log.Error(fmt.Sprintf("Unable to execute select revisions for org %s and document %s", p.Context.OrgID, documentID), err) + return + } + + if len(revisions) == 0 { + revisions = []entity.Revision{} + } + + p.Base.Audit(p.Context, "get-document-revisions", documentID, "") + + return +} + +// GetPageRevisions returns a slice of page revision records for a given pageID, in the order they were created. +// Then audits that the get-page-revisions action has occurred. +func (p *Persister) GetPageRevisions(pageID string) (revisions []entity.Revision, err error) { + err = Db.Select(&revisions, "SELECT a.id, a.refid, a.orgid, a.documentid, a.ownerid, a.pageid, a.userid, a.contenttype, a.pagetype, a.title, /*a.body, a.rawbody, a.config,*/ a.created, a.revised, coalesce(b.email,'') as email, coalesce(b.firstname,'') as firstname, coalesce(b.lastname,'') as lastname, coalesce(b.initials,'') as initials FROM revision a LEFT JOIN user b ON a.userid=b.refid WHERE a.orgid=? AND a.pageid=? AND a.pagetype='section' ORDER BY a.id DESC", p.Context.OrgID, pageID) + + if err != nil { + log.Error(fmt.Sprintf("Unable to execute select revisions for org %s and page %s", p.Context.OrgID, pageID), err) + return + } + + p.Base.Audit(p.Context, "get-page-revisions", "", pageID) + + return +} + +// DeletePageRevisions deletes all of the page revision records for a given pageID. +func (p *Persister) DeletePageRevisions(pageID string) (rows int64, err error) { + rows, err = p.Base.DeleteWhere(p.Context.Transaction, fmt.Sprintf("DELETE FROM revision WHERE orgid='%s' AND pageid='%s'", p.Context.OrgID, pageID)) + + return +} diff --git a/core/product.go b/core/product.go index 5b606d49..b724bc41 100644 --- a/core/product.go +++ b/core/product.go @@ -26,8 +26,8 @@ type ProdInfo struct { // Product returns product edition details func Product() (p ProdInfo) { p.Major = "0" - p.Minor = "34" - p.Patch = "1" + p.Minor = "35" + p.Patch = "0" p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch) p.Edition = "Community" p.Title = fmt.Sprintf("%s Edition", p.Edition) diff --git a/vendor/github.com/documize/html-diff/.gitignore b/vendor/github.com/documize/html-diff/.gitignore new file mode 100644 index 00000000..d8980a7e --- /dev/null +++ b/vendor/github.com/documize/html-diff/.gitignore @@ -0,0 +1,30 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +testout +fuzz +.vscode + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.out +*.pprof +*.svg diff --git a/vendor/github.com/documize/html-diff/LICENSE b/vendor/github.com/documize/html-diff/LICENSE new file mode 100644 index 00000000..99511538 --- /dev/null +++ b/vendor/github.com/documize/html-diff/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Documize + +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. diff --git a/vendor/github.com/documize/html-diff/README.md b/vendor/github.com/documize/html-diff/README.md new file mode 100644 index 00000000..fef895c7 --- /dev/null +++ b/vendor/github.com/documize/html-diff/README.md @@ -0,0 +1,27 @@ +# html-diff + +Calculate difference between two HTML snippets and return those differences as a merged HTML snippet showing the changes. + +Usage: +``` + var cfg = &htmldiff.Config{ + Granularity: 5, + InsertedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: palegreen;"}}, + DeletedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightpink;"}}, + ReplacedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightskyblue;"}}, + CleanTags: []string{""}, + } + res, err := cfg.HTMLdiff([]string{previousHTML, latestHTML}) + mergedHTML := res[0] +``` +![see example_test.go](example_test.png) + +Only deals with body HTML, so no headers, only what is within the body element. + +Requires Go1.5+, with vendoring support. Vendors "github.com/mb0/diff", "golang.org/x/net/html" and "golang.org/x/net/html/atom". + +Running the tests will create output files in testout/*.html. + +For fuzz-testing using https://github.com/dvyukov/go-fuzz , the Fuzz() function is in fuzz.go (as at Feb'16 you need to rename the ```vendor``` directory while you fuzz, and go get the dependencies - an issue with "go/importer", see https://github.com/golang/go/issues/13756). + +Pull requests welcome. diff --git a/vendor/github.com/documize/html-diff/append.go b/vendor/github.com/documize/html-diff/append.go new file mode 100644 index 00000000..abcbaac5 --- /dev/null +++ b/vendor/github.com/documize/html-diff/append.go @@ -0,0 +1,221 @@ +package htmldiff + +import ( + "sort" + + "golang.org/x/net/html" + "golang.org/x/net/html/atom" +) + +// the things we need to know while appending. +type appendContext struct { + c *Config + target, targetBody, lastProto *html.Node + lastText string + lastAction rune + lastPos posT + editList []editEntry +} + +// an individual edit action. +type editEntry struct { + action rune + text string + proto *html.Node + pos posT + origSeq int +} + +// Len is part of sort.Interface. +func (ap *appendContext) Len() int { + return len(ap.editList) +} + +// Swap is part of sort.Interface. +func (ap *appendContext) Swap(i, j int) { + ap.editList[i], ap.editList[j] = ap.editList[j], ap.editList[i] +} + +// Less is part of sort.Interface. +func (ap *appendContext) Less(i, j int) bool { + if len(ap.editList[i].pos) > 0 && len(ap.editList[j].pos) > 0 { // if both are in containers + ii := len(ap.editList[i].pos) - 1 + jj := len(ap.editList[j].pos) - 1 + for ii > 0 && jj > 0 { + if ap.editList[i].pos[ii].nodesBefore < ap.editList[j].pos[jj].nodesBefore { + return true + } + if ap.editList[i].pos[ii].nodesBefore > ap.editList[j].pos[jj].nodesBefore { + return false + } + ii-- + jj-- + } + } + return ap.editList[i].origSeq < ap.editList[j].origSeq +} + +// append a treeRune at location idx to the output, group similar runes together to before calling append0(). +func (ap *appendContext) append(action rune, trs []treeRune, idx int) { + if idx >= len(trs) { // defending error found by fuzz testing + return + } + tr := trs[idx] + if tr.leaf == nil { + return + } + // return if we should not be appending this type of node + switch tr.leaf.Type { + case html.DocumentNode: + return + case html.ElementNode: + switch tr.leaf.DataAtom { + case atom.Html: + return + } + } + var text string + if tr.letter > 0 { + text = string(tr.letter) + } + if ap.lastProto == tr.leaf && ap.lastAction == action && tr.leaf.Type == html.TextNode && text != "" && posEqual(ap.lastPos, tr.pos) { + ap.lastText += text + return + } + ap.flush0(action, tr.leaf, tr.pos) + if tr.leaf.Type == html.TextNode { // reload the buffer + ap.lastText = text + return + } + ap.append0(action, "", tr.leaf, tr.pos) +} + +func (ap *appendContext) flush() { + ap.flush0(0, nil, nil) +} + +func (ap *appendContext) flush0(action rune, proto *html.Node, pos posT) { + if ap.lastText != "" { + ap.append0(ap.lastAction, ap.lastText, ap.lastProto, ap.lastPos) // flush the buffer + } + // reset the buffer + ap.lastProto = proto + ap.lastAction = action + ap.lastPos = pos + ap.lastText = "" +} + +// append0 builds up the editList of things to do. +func (ap *appendContext) append0(action rune, text string, proto *html.Node, pos posT) { + os := len(ap.editList) + ap.editList = append(ap.editList, editEntry{action, text, proto, pos, os}) +} + +// Sort the editList before using append1 on all the sorted edits. +// Sorting is required in order to get edits inside containers in the right order. +func (ap *appendContext) sortAndWrite() { + sort.Stable(ap) + for _, e := range ap.editList { + ap.append1(e.action, e.text, e.proto, e.pos) + } +} + +// append1 actually appends to the merged HTML node tree. +func (ap *appendContext) append1(action rune, text string, proto *html.Node, pos posT) { + if proto == nil { + return + } + appendPoint, protoAncestor := ap.lastMatchingLeaf(proto, action, pos) + if appendPoint == nil || protoAncestor == nil { + return + } + if appendPoint.DataAtom != protoAncestor.DataAtom { + return + } + newLeaf := new(html.Node) + copyNode(newLeaf, proto) + if proto.Type == html.TextNode { + newLeaf.Data = text + } + if action != '=' { + insertNode := &html.Node{ + Type: html.ElementNode, + DataAtom: atom.Span, + Data: "span", + } + switch action { + case '+': + insertNode.Attr = convertAttributes(ap.c.InsertedSpan) + case '-': + insertNode.Attr = convertAttributes(ap.c.DeletedSpan) + case '~': + insertNode.Attr = convertAttributes(ap.c.ReplacedSpan) + } + insertNode.AppendChild(newLeaf) + newLeaf = insertNode + } + for proto = proto.Parent; proto != nil && proto != protoAncestor; proto = proto.Parent { + above := new(html.Node) + copyNode(above, proto) + above.AppendChild(newLeaf) + newLeaf = above + } + appendPoint.AppendChild(newLeaf) +} + +// find the append point in the merged HTML and from where to copy in the source. +func (ap *appendContext) lastMatchingLeaf(proto *html.Node, action rune, pos posT) (appendPoint, protoAncestor *html.Node) { + if ap.targetBody == nil { + ap.targetBody = findBody(ap.target) + } + candidates := []*html.Node{} + for cand := ap.target; cand != nil; cand = cand.LastChild { + candidates = append([]*html.Node{cand}, candidates...) + } + candidates = append(candidates, ap.targetBody) // longstop + for cni, can := range candidates { + _ = cni + gpa := getPos(can) // what we are building + for anc := proto; anc.Parent != nil; anc = anc.Parent { + if anc.Type == html.ElementNode && anc.DataAtom == atom.Html { + break + } + gpb := getPos(anc) // what we are adding in + if ap.leavesEqual(can, anc, action, gpa, gpb) { + return can, anc + } + } + } + return ap.targetBody, proto +} + +// are two leaves of a node-tree equal? +func (ap *appendContext) leavesEqual(a, b *html.Node, action rune, gpa, gpb posT) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + if a.Type != html.ElementNode || b.Type != html.ElementNode { + return false // they must both be element nodes to do a comparison + } + if a.DataAtom == atom.Body && b.DataAtom == atom.Body { + return true // body nodes are always equal + } + if !nodeEqual(a, b) { + return false + } + if len(gpa) != len(gpb) { + return false + } + for i := 0; i < len(gpb); i++ { + if gpa[i].nodesBefore < gpb[i].nodesBefore { + return false + } + if gpa[i].node.DataAtom != gpb[i].node.DataAtom { + return false + } + } + return true +} diff --git a/vendor/github.com/documize/html-diff/benchmark_test.go b/vendor/github.com/documize/html-diff/benchmark_test.go new file mode 100644 index 00000000..d784baed --- /dev/null +++ b/vendor/github.com/documize/html-diff/benchmark_test.go @@ -0,0 +1,28 @@ +package htmldiff_test + +import ( + "strings" + "testing" + + "github.com/documize/html-diff" +) + +var cfgBench = &htmldiff.Config{ + Granularity: 6, + InsertedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: palegreen; text-decoration: underline;"}}, + DeletedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightpink; text-decoration: line-through;"}}, + ReplacedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightskyblue; text-decoration: overline;"}}, + CleanTags: []string{"documize"}, +} + +func BenchmarkHTMLdiff(b *testing.B) { + bbc := bbcNews1 + bbcNews2 + bbclc := strings.ToLower(bbc) + args := []string{bbc, bbclc} + for n := 0; n < b.N; n++ { + _, err := cfgBench.HTMLdiff(args) // don't care about the result as we are looking at speed + if err != nil { + b.Errorf("comparing BBC news with its lower-case self error: %s", err) + } + } +} diff --git a/vendor/github.com/documize/html-diff/clean.go b/vendor/github.com/documize/html-diff/clean.go new file mode 100644 index 00000000..20ae5017 --- /dev/null +++ b/vendor/github.com/documize/html-diff/clean.go @@ -0,0 +1,67 @@ +package htmldiff + +import ( + htm "html" + "strings" + "unicode/utf8" + + "golang.org/x/net/html" + "golang.org/x/net/html/atom" +) + +// delAttr() deletes an unwanted attribute. +func delAttr(attr []html.Attribute, ai int) (ret []html.Attribute) { + if len(attr) <= 1 || ai >= len(attr) { + return nil + } + return append(attr[:ai], attr[ai+1:]...) +} + +// clean normalises styles/colspan and removes any CleanTags specified, along with newlines; +// but also makes all the character handling (for example " " as utf-8) the same. +// It returns the estimated number of treeRunes that will be used. +// TODO more cleaning of the input HTML, as required. +func (c *Config) clean(n *html.Node) int { + size := 1 + switch n.Type { + case html.ElementNode: + for ai := 0; ai < len(n.Attr); ai++ { + a := n.Attr[ai] + switch { + case strings.ToLower(a.Key) == "style": + if strings.TrimSpace(a.Val) == "" { // delete empty styles + n.Attr = delAttr(n.Attr, ai) + ai-- + } else { // tidy non-empty styles + // TODO there could be more here to make sure the style entries are in the same order etc. + n.Attr[ai].Val = strings.Replace(a.Val, " ", "", -1) + if !strings.HasSuffix(n.Attr[ai].Val, ";") { + n.Attr[ai].Val += ";" + } + } + case n.DataAtom == atom.Td && + strings.ToLower(a.Key) == "colspan" && + strings.TrimSpace(a.Val) == "1": + n.Attr = delAttr(n.Attr, ai) + ai-- + } + } + case html.TextNode: + n.Data = htm.UnescapeString(n.Data) + size += utf8.RuneCountInString(n.Data) - 1 // len(n.Data) would be faster, but use more memory + } +searchChildren: + for ch := n.FirstChild; ch != nil; ch = ch.NextSibling { + switch ch.Type { + case html.ElementNode: + for _, rr := range c.CleanTags { + if rr == ch.Data { + n.RemoveChild(ch) + goto searchChildren + } + } + } + size += c.clean(ch) + } + return size +} diff --git a/vendor/github.com/documize/html-diff/datafor_test.go b/vendor/github.com/documize/html-diff/datafor_test.go new file mode 100644 index 00000000..449ab6be --- /dev/null +++ b/vendor/github.com/documize/html-diff/datafor_test.go @@ -0,0 +1,1520 @@ +package htmldiff_test + +// from: documize.com +const doc1 = ` + + + + + + + + + + + + + + + + + + + All Your Project Documentation | Documize + + + + + + + +
    +
    +
    +

    A single copy of every project document, securely edited, versioned & instantly shared with the project team

    +

    Gain all this from your browser without Microsoft Word, Email or Document Management Systems — how much time will your project team save this week?

    + +

    it's free to get started

    +
    +
    +
    + +
    +
    +
    +
    +

    The average project team saves 10 hours a week by killing the 'find-copy-paste, send-email, track-changes, who-has-the-master, nobody-told-me' project documentation pain.

    + Documize +
    +
    +

    Get a tonne of crucial team input and participation for documentation that defines your project — requirements, specficiations, change requests, guides, procedures, policies and more.

    + Documize +
    +
    +
    +
    +
    +
    +

    Very few people like writing documentation — Documize makes it dead-simple to share the burden of producing project documentation.

    +
      +
    • Centralized project document hub
    • +
    • Approvals and document baselining
    • +
    • Publishing best practice project templates
    • +
    • Super-fast search - 1 or 1,000 projects
    • + ` +const doc2 = ` +
    • Automated document formatting
    • + ` +const doc3 = ` +
    +
    +
    + +
    +
    +
    ` +const doc4 = `
    +
    +
    +

    Plans & Pricing

    +

    Documize is free to use for as long as you want with an unlimited number of people.

    +
    +
    +
    +
    +

    Free

    +
    $0
    +
      +
    • Unlimited Users
    • +
    • Standard Support
    • +
    •  
    • +
    •  
    • +
    + Signup +
    +
    + +
    +
    +

    Standard

    +
    $5user/month
    +
      +
    • Custom Domain
    • +
    • Document Recovery
    • +
    • Priority Support
    • +
    •  
    • +
    + Signup +
    +
    + +
    +
    +

    Enterprise

    +
    + +
    +
      +
    • Hybrid Deployment
    • +
    • Single sign-on
    • +
    • Data Compliance
    • +
    • 24x7 Support
    • +
    +
    +
    +
    +
    +
    + +
    +
    +

    Misplaced, Incomplete, Duplicate Documents Destroy Team Productivity

    +

    Import existing Word documents and bring your entire project team into Documize

    + +

    it's free to get started

    +
    +
    + +
    + + + + + + + + +` + +// from: http://www.bbc.co.uk/news/business-35530337 +const bbcNews1 = ` + + + + + + Google boss becomes highest-paid in US - BBC News + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    + + + + + + +
    + +
    + + + Business + + + + +
    + +
    + + Business + + + + +
    +
    +

    Google boss becomes highest-paid in US

    + + +
    +
      +
    • 9 February 2016
      +
    • +
    • From the section Business
    • +
    +
    + +
    +
    + + + Sundar Pichai, + + + + Image copyright + Getty Images + + + +

    The chief executive of Google, Sundar Pichai, has been awarded $199m (£138m) in shares, a regulatory filing has revealed.

    It makes him the highest-paid chief executive in the US.

    Mr Pichai became chief executive of the search engine giant following the creation of its parent, Alphabet.

    The founders of Google, Larry Page and Sergey Brin, have amassed fortunes of $34.6bn and $33.9bn, according to Forbes.

    Mr Pichai, 43, was awarded 273,328 Alphabet shares on 3 February, worth a total of $199m, according to a filing with the US Securities and Exchange Commission.

    + ` +const bbcNews2 = `

    +The new award of shares takes Mr Pichai's total stock value to approximately $650m.

    Mr Pichai's share award will vest incrementally each quarter until 2019. In other words, full control over the shares will pass to him on a gradual basis.

    The Google chief executive joined the company since 2004, initially leading product management on a number of Google's client software products, including Google Chrome] and Chrome OS, as well as being largely responsible for Google Drive. He also oversaw the development of Gmail and Google Maps.

    He previously worked in engineering and product management at Applied Materials and as a management consultant at McKinsey & Company.

    It comes at a time of heightened scrutiny of Google's tax affairs, following the company's deal with HM Revenue & Customs to pay back taxes dating from 2005.

    The controversial tax deal was labelled derisory by Labour. Shadow Chancellor John McDonnell called for greater transparency, saying it looked like a "sweetheart deal".

    "HMRC seems to have settled for a relatively small amount in comparison with the overall profits that are made by the company in this country. And some of the independent analysts have argued that it should be at least 10 times this amount," he said.

    Google's regulatory filings for for the period 2005 to 2014, show it generated sales of £24bn ($34.6bn) in the UK during the period with an estimated profit of about £7.2bn on those sales. Page 83 of its most recent 10k report states "revenues by geography are based on the billing addresses of our customers".

    Last week, Alphabet - Google's parent company - surpassed Apple as the world's most valuable firm after it reported a profit of $4.9bn (£3.4bn) in the three months to the end of December, an increase from $4.7bn a year ago.

    On an annual basis, Alphabet made $16.3bn, but the figures showed that the "Other Bets" business lost $3.6bn during the period, while Google's operating income rose to $23.4bn, as online advertising increased.

    An earlier version of this story included a table featuring a list of highest-paid CEOs in the US, which had figures from 2012, not 2015.

    +
    +
    + + +
    +

    More on this story

    + + + + + + + +
    + +
    + + + + + +
    + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +` diff --git a/vendor/github.com/documize/html-diff/example_test.go b/vendor/github.com/documize/html-diff/example_test.go new file mode 100644 index 00000000..a60f8e68 --- /dev/null +++ b/vendor/github.com/documize/html-diff/example_test.go @@ -0,0 +1,29 @@ +package htmldiff_test + +import ( + "fmt" + + "github.com/documize/html-diff" +) + +func ExampleHTMLdiff() { + previousHTML := `

    Bullet list:

    • first item
    • 第二
    • 3rd
    ` + latestHTML := `

    Bullet list:

    • first item
    • number two
    • 3rd
    ` + var cfg = &htmldiff.Config{ + Granularity: 5, + InsertedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: palegreen;"}}, + DeletedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightpink;"}}, + ReplacedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightskyblue;"}}, + CleanTags: []string{""}, + } + + res, err := cfg.HTMLdiff([]string{previousHTML, latestHTML}) + if err != nil { + fmt.Println(err) + } + mergedHTML := res[0] + + fmt.Println(mergedHTML) + // Output: + //

    Bullet list:

    • first item
    • 第二number two
    • 3rd
    +} diff --git a/vendor/github.com/documize/html-diff/example_test.html b/vendor/github.com/documize/html-diff/example_test.html new file mode 100644 index 00000000..856d6fa4 --- /dev/null +++ b/vendor/github.com/documize/html-diff/example_test.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + +
    + variables from example_test.go +
    previousHTMLlatestHTMLmergedHTML +
    +

    Bullet list:

    +
      +
    • first item
    • +
    • 第二
    • +
    • 3rd
    • +
    +
    +

    Bullet list:

    +
      +
    • first item
    • +
    • number two
    • +
    • 3rd
    • +
    +
    +

    Bullet list:

    +
      +
    • first item
    • +
    • 第二number two
    • +
    • 3rd
    • +
    +
    + + + \ No newline at end of file diff --git a/vendor/github.com/documize/html-diff/example_test.png b/vendor/github.com/documize/html-diff/example_test.png new file mode 100644 index 0000000000000000000000000000000000000000..11bca0babb7ef0f392ae1a9dbb10063a798f7ac3 GIT binary patch literal 47685 zcmZU41yo#H(k>3cEx0?u-5U3xL4sRwcWE>P5AMO;0)*g@;0}#LNFcboG!mS5xc9!9 z`Da+G*Xcgns%ls5T~%KZrLHQEfl7i30|SGhs34;O0|QS10|P6Af&{#&__`Yo1A|Uz zD=n?AC@oE;?&fS|>tG23qY#yW;=Iz?1FNe|&({DB1AG{JBqEsn_r0j-5kzyimXYqb z_u;khN=)ZrS2p-HoUDOFWoYN-5gSFa_lxC`Yl2F3EoQVnXgc`#0`HQ$(J(`ZzVKcs zxW4sI%4YO!icBX$ti|m+D$H&pS zHM~9j;a4*!imnTZ*zl|R_a=) zusO1R@ZCn+pgZ zlj9NK39vsXcOmlkX5z%t&7)9Wx#knyzrZ1klzX_hEHYF_xHOS#gf1gl49P`XPzbFO z_kmk5k7NDTalZZu8-w-kU6Q~5G(uaC8xk4Zr~Zy}$}I(%v~E011;yt{ju11?@Ka6- zS`b}?^BKwn3VA4Fr~$%@H3|g;HOn{Q)um^zL&Z6*KPXTIPko4}SBl{BlXGz48CoFz zGuTcQG(>K_D%^$S{UPIeO^j2(y8I!xz$fK*v;L!CUdrX48}x(Js+8;qz2f+ejQ4LU zDT@&Nb!ajD!=G%T*t#*ztAE)Z(#*y1!7zB?+V_1i9W3$jpa-Q^hbGRyvs`pDC0mY+ zHL5m>U)l*89VfA(N@;giAIf>dw1f?N^C3gZ*y=6y3|3%b>nNw#Z!gxF?(tj=0JhNli-a+W;T6Q4(Ntn!TTNesLq@z^=ADEwV0zNNpyI_c9utP&9v4sm`iKt2=`PSdJP%kTB;|BN9 zFe{KGMV;bsag*vrrqEUdG8OvybQ#wN*%~8LTdE+DA)M zDF^nq;o7D@e!*6~=r|z#gmBO=wl0$$$Ky)cA|`!?kR407>V9VFL*Id1GdQs>aH`sd z_4GO)$K%Bu0+tjJbw+~XCsihTEo?8GINb5>_8Ao-D%>daLZPXb$7A^K_+1HHiCuYW z<9t5;l02ljN>-qAOyV1k##eclh^kmp99tYvoLqcR>@GHaPy&;oEa_$w*9{TO zaf5Ipd?N%_mz3?+>XxR~4=&==Gz;rd4PywiM_ob{soN*W&y9lJC86#;a2Hvg6X+!sVilk|`T2UK9OS z)d@}6Z>2?~{gm(WWpwJaQ8m|@#xy@`eAfB)<>IxTt>Y|DP6{T1pf zt5>kESW{bHX}=oOIxfGcoYp?lF48{NO0PK9ZZE%;iY>M(B`6+vV^G{AeH5clNM1xb z1HbEVD|M@SE9BcO{AS5eR9V!Z-7uijH_JCKJTp95u5bW7_Eqc#2`J{_V+6ci+mtq&ig{vo4W;)A6{wyttIQK=38K9N)d%=eY>D ztiSxZpEr5Jl~3wJdWt?rlFfS^Qqg^3zRfMbIl+C0?uj9d(I5UB<2O2T>}V`*%lS+I)66Zx5~8qw%qXJqCKNkFKPZ=JyJd4w*I!+ zcK>$cHWr%=ffxZI!4Cofwx~3xG@-OCw%^t2EY_8*m9Hx8=gJ$S`6hhpJqLArbpO=e z*Zwd+`K9i7@9@#V&QaKrxCy6;z6qnLW*{R*iM-j)@Svr}Yuu~VOXP^+SLM9gSB_fe zx}XiytuC)}x0XExcXY4ponO1x3&RUh2MzsuUwD>;ropxD(dUGOI)H(|rc>zP{p9_r z^2K{`cIn+>TC0%@W6Rz533q3&r`@&nH@mJw8ysq+6J!(Zxf}yo@jG!VLLCsuQ1n*g zlG6Ivh3fh8HrpB3h1reP9q5ejYU}zK8gOjAmwwbdagy4Z(>eK6{&WWu|6T~T46e2- zp{uT|iK;O_G=C(2uv@M>qr0&?fO?#|UP?6#SE^T9Cv5q}44QewkI+jMmmE&(o_QBL zA44C@>tvKl6f+r3IuapjH`M`YVJr-ODKQNHxO zQKWS+x5txr8BYWbpKVobUAVNjRJKm=v~j<+ZX3E7F-)FM-b&U^`~g8*)rJ~dM_4(J z1?J)9)Qea%2{1Ra$7iRfdB@ZYOswUN{hY{4T%rC-kb+8wNP&2OdK7x=N1TXf`B%_(c7LASQ(wxu$GeJA1dj+=qr_$*_8EvH7Gbw-OCz@huv!#eAar! z+Ft+5{cMi@8h1IVsU%KGfc-&#fcd+YlaBG5M=-J9d`aF>(DLc|Bs6Brk;U+>gPx+{ zunE{Nb>g#VrM3=X&9OdSYiS^xyW{+V_d#j(cilCuT2E2ScAs_&>AvuRSO!uZr+dQ; zZE)pC=VzznW#?^&j*fnBNN}~U0i-!_Vc@ryx8Km!tzG^8NAf;$S&`f$<;D5i z=-(WC-#xriPj2h7It}U=y(Z>Ker9I2fAiCsEo@w0$PGyT(|CflxZ=~b-E}1_XLKX! zqV9hhZ!#0u9>8?34l!%)MUMMKG4GKQ*ic1Lk*BxvGvNo7t+MT*Ape@KQnK~T)QUsU z?FQ{^PN|_a)7i4Qre(uNCaIKHucNw!@x{B^Ffr zqvmoGu?B67P?VkG`=(dLS{-ETmStQg&e*fVw_&WL`Z4pMalq@(RcYKAIpdc*L-7FG z(}9~TGXaj3kKcZ{imY8Ni6oyW9J?KNw50o;Ts{=ugScs;?v(eC^1Cd zk26WHiksb#t1z5y*8L`YA9@2L)5SAF@JpGxw5ROin*0P!U4C$ipS2KO9vRH~s;wVe z3>~BW2mJe4gf7Ch$;s92f&vZ^>Ulqy>{kgZcg0en*7uIn-(R-awGrJjJ;5DpIZ)c< zIBx@y!V4D#J$D!w0{Z6#zQn^`!&vt;*ibOCz9z<_*& zfv=919%fWNjt)-l!akxjfAtUszCXX_prQJ!i-)}^jjoD1m9(>)B^4h#FFPlV7%CMN z70AuPN?1ci?w{enFHssB4-Xe%4i0Z`Z+34Uc4s$h4lW@fAr4M%4sLEXpa+{f*vZ4p zht0{I_U}pl|2#65?&fZ`E*`edPE^nHn!R)O^bn0|rvm7LuFVGCf8 zUvmRPLC#w(fxWrIF9RCu%7-}ryW*e{@WVSMDTEG+Td24{bLg2&n z&lC7=(#p#RJ%NFdfKil@)bfEn40v&2+1u!SDT60PYh_!bGZbypK}4{g96>m7E|aO7 z$ru{1(1%Zh5aq}M@slWUF2bcMS=*&*dAT&ndp0{^}EzerIJ?HWp?-C)}G!Kb!7!T3K+ z0qf;EA&j1tlL{-@{0HTK54L1MK;objk;(DJHd zOu0h9S{PyJ?u7W${gi=oJN>)VyVfPI-z7HH&C9-t0;>@EFS=D+<^#neJqNHv;EjrR zWTYYw;SvJFzjyM2D01A#g=&?_eRm5|Yd!-l3iLFuVGwb5ndr9b&JSE~xBSN?Y z56&(D`1?+--#gk|i``%5@s14WDkWjCVHg67oQV%A{PV>up1PWnT<^jqlCc4OQ6xx_#3s=W^&to-O-o35_WJkD(GzAubscO!Ldc+(SSBDYE5cgQ8+ z@ayZQ-u!z*_hS)90o&=~FTXd=W;NAX>C<#+v=8r2I#<}fAJ$b^U-e?|(!nj!I47x{ z_y~3?S0ztcZnIq$P2|OU8 z%Dv7gV#`RhM#t2NKhh2zVHuC#Z`HHP=pW<%?clTw-tmm)=x@6)X41)8dcU8^=e@D{%tS)6B{)3}0;xzgx&hw=fZ^ zI{N~;vxuh#T62+lY12(KQ3$^<-NobvTGi?vLJsIeT4ZZk{ZLV7e-E`*csi_~7`P4= zpM^bzk9QyCLXOverR;AC|1`oMjxk{&#Kb98Ff3AeqE_gsB;EL9 z(9>yzxX1aJfQeKz^0LoH?58L1l>h-JX{O#JC3fPS-i=|-iSz~R^|q(SJEz-=z2gup zvB(27)z2mbX|FM@2^-cw%)6#soq`a5n8X+gY{CGJZyj ze}uY_&Ay`te|}cN{N&e01)2;MeSogm;K9{&KKk12FQQp&s=XQ+&Ec1zp?Cn(=k@)O zllA~k9L5u-xHd}fMOQxikbs@!*AeY-SYp?vn`#xWMUmN@-^*}|<=!R!2_;0m-Y}+Z zJ(PlO#P0Y+VV4wqH?%{{{W@!tZUp$tFL(pW$i}jTl9S4glOn1tQ71s>$_;b+_7xY2 z5ds=^UpI)&HmsK^&?m1UCXcv)Y1xDH%&tG6u@7xVZA4)_E{G+F9JkOWkp?Cnx1EnG zZHYQAG}we-@DGjJA2t4r`#P%n-J)YzFt%+2S0!8UP00><`H%=4R|Tna8<&*Gs->jQ zxX@0_myTOIw(rvukC!z;C39!zpajPK7!%zO_1l^DbEoTSQk4~cv-D*Vr=?j=nfk|b zk%mopnx`*_i=g?BE}wcU%5pP7McyqnE$bf>^MW@g>DRo54U)`EC7^>4S+k&hqmQo^ z`iZTx3*H6u272*BLoh0M?~y&C4Hsm=Q{;YvZ6V{yvX&O&N_izHQIxv56?@*NZX?WP zeSZBd>>*Va_se649;m;e|njIx8kIYh3NPF&y|8o zi5{T3>9d{P)r6Y1;(`Lt*`J2)D$Ico3g(;grQ~GHjXG81# z6Zv%WYchFNK2RZaJa7TVYw2)O_9UdhB2jX;A?mOjJJsq@lRMGC`)jF%)s6fR%-2F_ zdXDMMQ&~>mD#H2qU&5n$@V!bu>eGTKRr1`R$K|vwP&;!^B&=lOu|xX*_;oRdbfmgA ztYj9&JUHtwR#_XSrzHmL)+cD*j_e8x!6cW|k4zT26&hV^w9^40K?c1?AgS5-b3Lj#%jWtmi`3FPXCu5o|c``U{ct!NJ~qqU;veLVRy z#J=1CDp^hgs>|N5s+)ATyUP}{QrQid7xA!;Ozu0c|4Kdi3h?f1Ue?JqyP??R;HIG$ z)NlOkMyAZxIBkeQbmb-S!73Z5VT?;3xaRv=aj{F+Qj}mVX#N6LSSnX8dSb7;B9R=& z%KNJ_q~6OPH+#bU6OI50noUKns3oHxa(OuO#tp%a%}e~LSTSOq z{Cv55FrB*JiW`yF=Yz=Dj8Q{Z2Fcu&v&m!Rd?!wH-+C^2{*)D1bP4%(j|x673DmpM zFpvo#_nduWXFT*Lk~S`~Qxa|?=RDX2v|n)!Q6meq~zEaxw-WG%|UNDE>7+#S7` zA~M&>pb~(B1EqcMnk@DnAfrj{@>TW=Y6(S11{;)Bqc##eeh`YMsz6*4 zNb3ltfc3ylLXsQY19aGf!Jin>3h};lR4|GlPlRH(3lntO)i>0?`*o#UVZPs+Xrr!o z9iqiM2v1IqP8V2!x8s4mO)kE^O)RCaH^fxt|GxI{y0w-b99GXDA6)xLTF=Faze;4* zpf3C=#bnMX?ro2$#NDb+8tgCxVKCwA+!f+*iF|$yo52TZrSvq81@5g7AEufok^q%} z;d!LiGzyQFDQU3Pl4Zb9Q;dhpv_yI{`QBF=HAkzEGD)J#SHHb^HtTXe*?|ijeo^*u z>@q~XSfDncS+E0d-1Fk5`Hy%-UcK7LAG?Of)|h`6kL!%L$eezQxVJXyG9M8*V2X(D z8B{J8dJ;W!wW+qIv;|8(Xj@D)a$V49JzJ8(Hq0}^V5y!}{WGoL-RcMPkgs!;7GE9W zF@l?@0O#Jov`P8%2N+?licdGCCMw<5j{7nhrl+T9;UAhL6Kl-ogfrXXRH7%yv2r`J z-$tCnl}V4U!@#Rb^H8+b%YgIGm!z@>IWQz`L8qb=ZbIn7x-p+1N?&H=b`du9|MRH8hC6VU~oriBtLAtCawsk|2%W|A0Gx%)s&77fT_p?0v@2HA2LT^^^O~ciA zI^nReQ&XF(G06)EG20hBNgdLQL|1GqM@f*2r*xGO(NMnIOnc0zO~YXZ^(5-EDk6TCtFJ@JpGhKL zwX3X76U2rZE&Cc1UFwpAULFNq_fp!)c_{8}jEkt-POgip(vEy;j9tovC&PIM+L!7|WY2{DuXCs(`5@QU8MMbOjriuAz6ex3 zYil@HptNbKwwyl87ZK4+m|GKu5v=;GQjF@&Ad!#n`747(;dUGHPr=Btw6@u19tdt= zRJEe83UdVVv4o-hgt~P|970i;-*Kz;NAFmy$C#M}a<=swXZ6!}jAq2?-bs;k80gEk zkVKJjHDlfFU{M0_*^NjH<~y+5F8zTb6vj8RmM%R(y@SX$^++j8yYTv&TbKhG5RDGI z5ghqmn+=juh8wOL6jN-I6>~?3qY9A8C*tYpZsO9dh$O6gC#}C!D1DJt&2n}DBYnwh zi1ciF$Oy_z9#0(1cz(v;W2@M@cGkdYrMM*#JnL#0k=ic-?cUOv9!i!RT^`o#u;J+_ z4p~_c<6bsy;Jq5fwqblJ^C;xd;O8+i$bG(Zf6=t+NWWqxk@XEROYf`rA|IE=>Gf8UgaV~ z5|nRl8RTlojarC%B&kZ(tkpeQ5ElDWNuHtBjs))h1Ko}d-R&^20esU~3mu1ss)fkt zhFVAO+3bB!2S%%!a_L&<7K|ow>)MU2nNW1_eO=noh#qR3IGJn3$~jql;Z@<8-2{5D z7Y(rQB2!ImuR^+P%W~4V_f4~vw#Ef`@iyv0B& zi3s%`%l_AyD~Cf}*-n@C_bx`US*C;dbV4(+gW{>g3A*FD>`1^|rt@jO=`Vud*Dq$& zCaQR1)8@kImfP4PYq+Lv zwi?#5*K=5>tDbCUJD#iuoy1UvgQ`R4;j$Dw3_P;KZcms-dNKmZiM4V&M>zkruZX+b zV*)E6dZjiMYS#4G*NcLsmXOLHq*tG8baJa`JNi_i5L-AxJ+WnDA44=!xEzTtvUt^e zC$JY8Y|NF?7Hg3CQ+S(2L};Ah7d$!SS89#xA59JtuKhBs-}uinpNX=_C`~8GHLwzX zO<0M8sVkK1CM$D~skOFQxu5w>h3)O@rb8PAO{3N_d4D)|$&G zlC&{J941Uk4ypWdbL7~Cs=g)h^{F9_4K;Yv@n$u!EdDXEFQs>WG>z3l0H>WoUBLMACimN z#!|n@{Z2>8by4Q)vab!x_IFl;61m@<5s6SgzN%p7T?=+&H{)8%Q=}&W1fcF8vXy#xijt3Yd|_M<&v{uW#+F3e8;#X$+FQy z`MYcLIlZ&9sQ#|%%fJI+GxH({_39)ogZ zy5{gzjCTUYZD6dG&&EdfK9-q8gnnPOJ>sQyS3G5!f7}K-@71vFMAV*R0{;_Yp zpLQsX;3;L(`;6=fGhr3wv-%4}&a~rj)i7#z=(Sv=T zv&zPstVU{7`LPMH#5@em4w*P9KY}OSi4-q94Xfd&V&vWxGKrN=ZPn3?2%N;JCbP5R zth&~+>l(myZNyNB3iH2@LRuyk%dj%zafFtcrjk%cWym?LNcB(m_A=#MkG@~f3N z+&~E@8P>TOJz44L5pS?KKWrlQYLn=asAg_-%Ueh`D+^gZE;t|AAGERJhqF!=Am@h! z2w%h<`-`Kk+Z?Roq;veVd%nVLMdOecR?vestNsp{eFJyKINjy(f7!$_HDUw~#)LRb zENt85%7t@u-a|9jZR9I8g~hNnko)65{1Ug4#_d9vCOi;N@icUhH#A^%6f9fZ$t|)LMLX9y z%KYs!U%;z6elXM^%@;|-l?rdHG=i3Hk>4Hy`Jzf@(h(H$?%(tm{j!8c#qWZzKUEB@ z%FcyJQZ(>Y{C=Uf7;G@t{856?v!GYW+nL+ zrm*fpqz8#}zGMLQ`hq2j7EZAGpg9cc8mYJ2%{Uk49fsyG4}x4A8S&HAfxG6!Q3UlQ z3(7TS?~N$_xVM{A)4Y{Ckd4gC0^CCpeNg8`-wj6exc8z{nx2&_8b_PUr~$1qcw+%f zy8<>J#-ITGVyhdX!I;^+_mQ5x5#{Cz08t8ilpDBoBW{Sqr@urBQi%8M+L9;A5irj2 z#(x)BKdrshD$tTGJ`cH}=f!kH-E!t1IAUiRS-0j}|0c0qj@8f)U>FVAsjo&#SQ{vr zTv)0blFp0HhgrnUx8CZSgp7{NLGV7Nz=7#!zGTQcNO%d^)_;LV`aSJmiT~~?Al>l~ zq=OwPk+^}QFkYyGAI#RgIDKQ8%6xoZfZ{Z7nXZ!CT>#|~8>d7`0-ZxNb5_s@MDT{C zfegFohxbAhq8f>B(f`Jhf{!KgNy)HcuI`*S1v72Sk@ZGh0-o+xyrsj@D;U8)%g*Ej zL^@etX=8TEjO6&NM{%)#QoMq^HD?TwhbpP(h(nv%ctSxYfS+^p?B{spJAnU%&#h2R zV#GzPh-?I26jAaSS_eAEo%?Z7Bi50Ka+)E|p`?A{wEt$L(&VecXV5!i0H zJ~zcb2%awztRMx1qqFT?UWw6i-4B!$L5|J~IV;z1UBIXipPqXFvX*Q)M}1LvO9Q0N zhQb}Pya?Yg0PO2q^+1ftKP-NcgNYmD2)a?)QFDxjti|(sJ^r%TQ4{{G+-mHzhPV^I z=d{~}o?^d0TQN@gV3^_N`2ojtwbRMCzWC#L-TAo4cOZE)_W-2LH{;nHP%g-TW8%Uv zRX_OOSXsUu%Bl=kP+N2FUWi}-hM(#7C-b=LS?=sp%XI2VtY>5ktI@&ozi~w27zriv z__f}MKS!l?m_I8mo&O7;)WQv}TX|x6Adfe>Unku5(5m|!%luy`V7@yF@6y?>;Tu-# z|7rmwO7NHE)e8sQUf@GYtU($ThY|l@gZ={>LmfL=BNa0R|&fUf^c*s?}pLJ39vBGp4d44_y2IGjQ? zK8VDA0D_AhBT;V5Ge}GHPRSI7moiwr+ffWzZt9u8*!RQWN*w-Mpx2}mg4AWE5XI3K zYRCk(IyTBn!>~|MZh-oa0QJUasN7e8c&Lc}rk=B}@kIxKv|O*Hn*{Dz<#^65pom_F zj>HrOT>j8`J~5eD>D5ApLXff8l{K9aG6;85Dk#~=r!k2*yD&(2QM%I%3qJhDWyq9C z;baZ*POdwA!JQXyl|d@#VycnG4VBc@EabLja@sY5MqF50bS`@o+vP(RpGS=NeT8?ngs9<<^Sg#f;4rXh=n8tZLd`i}_Ui9d9h(SCX{=;^^VGhX~rP~R%U(ry{=sP51AlMa#6vMpI& zuiuW%%3>zqtyE)*dCDmj zfhBw}d<)9@>$az#osTaAPP>u$+LSYSD@u<6icJYG|`JCp8av= zNZeO;{Chh^%#$-tg0DsU<($%`XK7YpIi<%;GaC&E|MSo6QJR$Z$}7&D&A*+#YYn0n zT;>L<_2v^_4N~|yIAt{QZZdU6n%Gs8Xb4&nvw$a}a?=P)Ld?zq#I~Z%7(g&GKtsMi zeAs&=#xAlV+G)IxQX-x)VSX(gK(r%}#Thkma>tgna2$bcu-_!QpWOtA0t>>M?Ujq3 zz>2>lB$`2}_8kDmU7Ix40O(r)u+26b5TRMZNEKS(#m8)K*x7-1iU`FH&UM2K%!AS$ z5r>4sCCa^?Q4BkVc_}a4eYrVumpwFxt4PRlS6$PGe#+f1<)rq27wIdlyHcM< zNH~hd6nR(6bOPK?)$yQ23EtMVeDT4hjI0mzr%*%w+ds&s;jnf5e`Me%h4t z@|ghcG4puQ0lny6pb)_S^C5TaEb%k>vljYi$OYsc{n6%!moRV|O(kNfC)9(oZpQ&K>Z9bY>wqS=}h8a+o}ujUYlvv4p| zTIYfpWL1uJ3|(bkQD(^Pqep2IqbH4iqr+a1^j55m8Dp1|*vFawIsC_RQ=^n?X|^Au z7~!D6x7utF{*HJuV~P@;``a_%ybAzS(E#qazZ*{K6#0Aw`<5)5DdUna?g6C_5${NJ zXD~7s!ghWQMYfeHXW&vFXE}FN$j1H*DM|)161e`idu0_ZtI6ysl$NF9+<|-TUO~sL zJGh3ELMuQy#4v*@o0#avy&J`@=n@zdN87&h2dFjT@5b;%SmbEUEX#xo$7*Gi{6kfb&6 zT&$!N7%E7Sz%q2z_|upaauh4DOav5-@O=?iiBp&>=J}}dIJ@2YsQ3vATih>axr==3 zx0xt!N2Z<|9x-LiS%d_p5Ad20{j<5xd&&)Kqu#R#!Qz0-GF~8A% z5z=$)B2E)OgP5W4M7&1SGi%C)#$t9?;KMCla39Y zoD)vdHU)VD6f$+r`8ttl1SVqe90~N(0SfVYfrf@n)ZTS9$tNlT0Rf-XYxWrCt)v1Y z_8Y^=v077L%AO=DfT|pJ#WLv}lw*;@uhO7z3}|7hnclA>(LxNJ-uAn9Xd#W*0qkm> zOBuq@#M&GczeH*DT5BNl_?#~rq{QB8LDK-u!PhT*AuRZSXpb2c*LDJAY^Fvtc$gLU z*Yc#W~50{f_u(auzKq6c}S8>7W9zY%0XvsjoRIK_GE94n2P1 zH__8;4J^bFPidESamdu^9ZE%S*Ta8t@?(nMpBlCWKLBcyuHVF@X0moEZN?^^O_xgV zZKIYDR)sbYF8+!$U1zcdDD}{!8)=X%h7T~T%P9iMLaAp`5-~QlOXINPO}IIFvW{K0 zD_9lEhLQVAz5^C+1sqTm->Jy}Ymm;6@=19BHD*QOF@EL_pMf*+KkFAnLs!m^)x0YZ zK}t7Ow>G-`g(9OgGO|~eM`7j_4=oj0KTE#s!fM~}K1B_nO{WHu7T=hSp+2{Y3d)(Rcz!dl4>G_5JN$^vI3d+jde&yLfiFq+*jJ#Stq zp*!lA8gKPMW#$ajDSAkVYVr47j7Bao#Z%R6os#}Xkw47igu)dnas=gguEXjiYh7~d zdeoI&S~lrj$8k5g&s<_G-#$WH)8a?rZ8xVrB?ZNxDlW*5pz-d%F-;OrS@Z6^GkW!u ztSZcG_J%|;vJ-HY%hr`FS!ePcrW0OsGvT1TT*Rdl!IkxzC2<1#*;oyW9l)R2i`#~H^Nr->)pM6zPF@Pt5ZbFak92%$ zW)5A;CIevkiYD5P)n+nfxcJKj6fH5wRZU11C8LSlj)JvRmSACariQiByu9IzN_$yW`Pff)tRME|uAoU5E_;cYG^X;>gceS9qJzXl%p!YP z)adC|_Vk}aI658+f^71}JK654uU*!NOe^q>WOD>VJFB4U_am4(UL$&Pa&JI4xjPvz zDMY+jUkY^C^S(a;YMw|XVIkr%*yKK|!OUcd>8$3jlAQw;O47BRa^FIcH{MLIA$^XC zhld9$U8?XqHHhtxv`I9w%L-k}R|%#LX76ag3DA@u+q*)W7z6NMxNX-~lQ)8=BnmaR z*>kM*(r8FlFP{s5z^Obb`ufXhmUlA#hy7iLUs4$FkqF$HQfHzwhOQYQ^uL?Zl%dUA zX$ErgWUex(Cd-eO{zMYbc(0ZJCi50HQOXn!NvC$e9E+PVM@Q!JtVL0-bwYrXCa)cB zevHOj-VUlipSruW8)_7l;;l81DE&{nQ>rXVigutPnya#y%Ib@S-#2APxTmw6_C=RM z`87{oe*USy?URou(<^WNfgVrayb~zSNOId|rmJd=Fbzf;<9`N+`FI5uY>H4AiA+U{ zn?N5(2{^6j)Ht(m!e%Pongm>GftXh{xD*Teh1D~#0?lo)toYg6FEl*0QaN_u)ao?H zxw${CuhDvEQ^us3va#XwKc22}36apACxKmjsn@vW!nAyo2#rnf)9$;^-ct|B*GNWO zp(%!30VsbgJCIPqSFJN{yc)saST8vg)pCJMJ9@W)z>}OIy&pZ7%F$+V#*NY)BNtu( z1IG&-t~v6>;&a1PX7k)%89$Z%{L%kd}Z7?ZEHdnrD0O2=4| zWQ)7qHgprPI`<#GjOW;r9bsG7Sh5FsZqyqmp8MAR^nlsVxPY-ZFE5IF-H5krwR-sO z{psyNO-&T-@1P=nxDh7HFrVQ1TA-M%52U`5;K@xhPfwI02-N)9Un8j$27{=@ueY(b zWW9IMs_?rV;BOs$RlUVFW>}58;!^@fI5yc2kUScJ|B7*)THnanobb>j(5UvK0Jd}8 zMOdRAq9AH|{3n~DG)xm?e(;WoLl@2dg3FqR9M9+Ln zyRoYSxfG}bJl?&B=fTpwiw#Bq=l7%6_F+3FI+xQ2@&*c-SoT<2z~5~Bz&WEmNfI~3 z%vc{MheiaZDe0Y&`So90xu?jFM5h?^F&EL&)o4F1JzLN~rs13K)R_reZ;IqfHgO$; zvB+rHtsYwpPp?+cNnybXdXj;kaLQoehhP@iz5p(XKtI;Hl)%u&5xEiT%_7CrLeatJBEy)N!@4z=wmIrL_%RU$fot zEEN~bE?5H|@m`#~F?_NdVtget9j{ci`Jfxs{Aw)-g>>>d&r1X6WQcbI&JV}M_QbS& zghfrg!7~#Sq^jgTO66gpKCGHyKDdY9KO<*Jmv$XHmS4`HVF3nHiKQ58|M7ugiRpp! zGk!aoG@MAyom9-7jH+&5Go7&h>1CKSVsoT%+49aX{7zKdbiY`P`28AI1uUGgJc^QG z^ghy!f|vwyJ)WUB8Boz%f#cUloe=^WA?6+?d{_no8g2mtf?--S8VJI|r>M$(3anLx znBtA_M7>kxU#qGiY;~#@?XRm6_?1j>otC`*x`MrdD|pI(GVP8=ksaJo*M2HitH=Mr zp?+bN_KeONs}4yO$Asd=_#L4lvKtJjdjN3@Tn37fO8U^PyV*sE*1uDjfCL*Dl=^*}Lw z!$stJxO$j5Dn7ML+HLh~gjS)Y4xVo|KvP)DbQp|>6bYFG;G4r?$Xo0qlwTChCscLc5;Dn+tx^U67 z>Ox`-AZ?Ol4P!bW0Fje-X{)3-e)e3fRh*}xa;lnfzua4keE_j_6aZqIwI-qLi$Cn- z`bwX!_hu19&Oi>!t^_tS4s0DIgACbXC;R04QE)`ku7n`}?Xif?K6@-G-k{Yj`bzleA`EaczUSZ`rj_B#^-Rf_3attm&VVvzoQhB7(nvLK%!DIZJ3b0wy|!D- zdOe8VLesrm+h<>c5KidC^g3H-=)sbiRo@Chjl7mIs1+A=Bhojk?B|8NoW5Jr*m}m? zNfsS#>1Fe~5Q>oZj)~dwHCN|9u)b5u{*kybhbYTg;JBGfRwH$xUR_ z_Vz}vW(eF)Wbd0y*{kePzd+hPXw*cw{Fr4)JH)SalzT1-)G{Orh|pkx*E}q9HA?FO z&!I}jyQ|3SsVgPPgJ4OJ9^rGey4H5qW~rNI1f|*7XdaE8{^T@0X*X7{-ah9s2p_9q zpcJ_t&fb_rjwi|R5)&Fq9cwA0D=Zy!9UD8P3k|g<%1JJY<&>)}4o2fi)0I%auCKyE z-+u9Npv=R+T$zN@P)|XBHD1+{hNQ*5p0#ciBzD!dI?L5Mo}5l@CbrKC?!E&A+Sb4; z8~$?ob%};t@NkM(D&!?PMeT~!H$VL zv=D^Mx;n0eZF6!BBtE9hPn=IcBfg~k6vN3xiYm7d< zNpR(Ymr5^HXjE}3%kk3xh^aG>AJ)zy*ofLubv*ar-y;`$+M zwfaiH6XHd)XH%c(=H3dbjdSTX!`q>mOPr%$Os*MncmB)XE%R{Xh2JI;hI9jT@AZ z?vQR2kQV7fC`by3(v6gKNP~xNX%J}?0coV;(A_90-6?VC=DUx+?>FCmJ3G6xf9~u! zgZ6?s5rfQ~mEwBc zEc=bOkQC(tjO%G<@4|Z>l8Ij=Y~0@x6@rpN-t{*OMCA3RLf2&C29ntMz;R09op&#< za!IY|tHf_rP)+A}uMXYl4d@^_VN5dXTMK(v=yVtJEkHn}TlbfU`5?w(_Zt-M9_*z1 zfk3%%<}Up@!#CLNx@(V<$0}=gF z8Gl!})H=IMaPYXq-NkTiBuOuET8CXNDC+)qp#_eB5jm<#8Dm7|cpHrEJaqqK+d?;5?F7IZm_P!rfQlmOZh4`)9XTePGj|Jrgc zNx<>`T9~us0+baF81o4lhus%~bJDC;r-(2aWIc{;1XA5hXIzUkx99IZ<;IwHcYGPe zLBV(+@Z2Ob0D?t!VZ0Uh^gPr&!(t$MG3VTwn}}pE2ANwZ$Qo#B2*rhD+z&(pLq4*u z1~oFIw6&op8WH$?I?cd_kVH~r%47)9l5`Qsd~lRyT87aNL<%VJu8)(RPyU^fcrYdC z`&EkToul^xiayZJ%EetcnFT|tP9O93U*QJzl)h?Rvn(VTibofYL-!`2V{+x8RykW} z8{vt^tCm6E^_0REJz~_{qVe{no@DE(wXs>z!*1{mJMO-uYnzn%g*RHAHu? z1+)GP^(I%bzu^S8lD*X~q_k0WzPzzVU<8NiS+(~3UKl=fxZH(jGmL4cVwxu}LR>*q z6@OvYf5l%NQ%7P5UGA9_7lZ743x=XDoRjzBi_voAk$-t_y(FY~NC@vqWDyl@Qiv2> zMkkqUW5JnNw#H=%ocpi411QT~llqzdUYK~P*K&!ULcF_ZXq2&+iim9vm48UqGd}Y} z9+4qsw!an(RD+Ij4;!spnrUId%rSbO9twVByPU`B;~*7Z-WXTcNMT$Ha(<|KRVW? z$MS4`b=rb6(mR;A;XIMw$k!RB-**~(Rvzh4j{&Ox86W$7HpU5~yW5{|bKz^(%X8Vs zUnr!j+F!+JIW-kN_#0qo{;vax$TI#rkRe~#(V4zQjX)Lar&0?#`#po7X|4{IdR}^t zB*A*>C8>*t+~@zVhK#Tqg-UF#oOQQ>qTD2|%ozXv$7K%V)!{WKTzPC>m#oBl@P*WnzsK9z0h*=J&(r?TInqQi;c+^B^5h{FE!_ zfrOH;R(U8_1WN0X0ymE%nUhP4G@Y|foO#r^%l~}wXYbcbTzGLvAML>mIoxx4z+g>+ z{nQj40u&h155f;)Lip+FY%xtA(2Ox0V>BO7@lk7AzRUasaYuohQ7t(WezH}oeov7J zwN7ss(QWSjMh$YW3Y=}E$)&#ujMDd@KW*c#FaYGkVfI-J;x)=d+5PCr#3So zWbnecSl?SS3w}cl>j{)5tT+^t99aO2VGs)p2B&f6Rt%_KTkK zn5LIM+%moZCA@Mubot!aH-$o;Zz$;!(DIbu4dEUJBDbJv;8H0>iwd+^UCA8GA={LN z94;^L!~~Q7Y|~M(B^FMkyEZDI%$7M!`BFsJDcgR?^;@2vE+J<#j)q`6aJcE+)|$+R zFr;ag%~#rv8>3@cY-booR;g|{(>*kKnk0_`;?MC(^%OL#yeK?c%EfRqe`d>emlq5Y z^}JtUP<*u+7d0V%z;Ao;gHr*Wk_Y)!`zoNdS2}qDE|r7)F-`S)~bx1VGeV1=*!kRjrIL>tEmG z+3J5yv3Rm(Cuk1gi-+q}He)*FY|(9U!s0^~<$epyjR9<)vp#HEPwebfqrko7^WZeS zCWda~JBF%N3S=hPsECSjw_y+CESi|y=11JxgK^)_Cp$oo#hdT}xcZkf zQ86f>OH`ALREm=(sFkMq#36Tfu{B^0Xtp*Hd;oLvQ4$@4i!Rvm9%;f6TIf+E-+G-5 z8q|5hBZycQeFB@KO!D`)eE086&0X^sE?e*;&kK3ND!NvTz&?EkG*ZPy8XKT@8}8i2 z6ESYOSbzV1Sj>$eDaOO6UhS9bGZY_fGG~-kG+S!2RXd<1bRAJL<7!5K{7H9{>_9~% zmt#TCJXX;3!P7t6bf}j~LxpM;#npsaWY@HB1OZ;qS&plZdNE;2y=w#zVfjUPSJM$n zG(zIr%SU^F!sIA{n~F3!@WEG8d6hj3wyu{hB%MjG$!2Tae#_D|)3%v@n8_ z3ynx~5&MNLAOxf$pnX8Yd$UVfDi#5d_)`u74IZhi5CF07&-HZ{ATg`kljDz@4JxP$_ zk7$dh?8Dd2ly1euhMLgzJeR zX3p~=PZWZbfdPhyG4M|#Xq+<@=nZENoLt=7-P=m4#_#PlCGwoV@97P7e1l!S*vcpY zYY3n<2&Zv;LOhO-oMM1-c6jBJ^Iz(Uv&s!so_@G5iC%mISFxPQ3_;JcmQ@HkwHIQQ z=!f}^S!>hLa_<6*FRZRg@HhS^jR?>r0D*%PuzIGkYRvw3BFZs>h<|L+sGI-4$^QMS z5nOfMrRo9Dm;cr4!0%T2ud@G`#aqKlD(eJe@wfoNTzT@OPO;Tk0>`gJ7R>KX;RqI@ z5y*a!Mvb$44fA`L3A;dlD2=+=Gh6hAA?0&oEP|(j#{gI+42zt)2xbTc@(aYAOA)=( zmj4KpX|foBP~W`htRG(~k;MYQ_zbJ%kahqLNYgVg=!xRWN#>9Ncv-di|67L0d@>fL z+rmbAZ|#e^J$O6==T{q3TtA0@q>?3aT`Z}rEySW9rQq>L&`q3BUk>Tw{Ydc>rhUwD zIzsRc>mQdTx5Z8x$FB?UPiDKED#j3xVuD9S{p#O?O^D{!UnTKxLmtaEl)cuVMl3OR z$G@bRR|Gu5nv$07OkjTQm7D#n!3f;ue-F8=&ev)!3`8vOFt?RX(C0odQU-W==G{-a zvww$Dib*Z%f_Cb(M|C6EEMHkKKcPH)>V9CfX1PQA0Vsia;fS4>hzS=lYPl!)ZX|20 zq2L;@U%20DFqJ|pUUfKN#=L0O2thYBR(+3{3hLLVePG}ohf9X09f=oy7n*2ZXF}~>S)yWTz-+Kf zkWRDqdojmFCbnpPGc@ViGC-E$8WMG>dPwV+{%C&XfsT{uwl<#+>~dAguDUL`u5R6s zIkZTa_L+nB>H{W%uahkbQc>uFp;CQS2nPlDN_UOv#L_>p{c)9(FyMy+`vP0C3bcn! z*N6SxU02sf!~6f$-xE}0uQVOBVcP-1j3c-~A_0SQ!+#6Zdr$XjSE3@0>Hx$%hs9nL zbD)feh+{V%DW!}(?ao%sz<%}vBL~sL*V3GEV0Wuw`4I@$-16(YL>{XV#blD{g3Jfl+E&RIWpm~Sz74(~(h5@ zYqFc+vvX`u(iZ+dbyT(|^drZaA3E*k>Fj%zi`u0Hk0^AC{bC1*Z)dd6waFQvDb;#z zwKIr<`7yz%UGc-ipmRXo1(p(nbAY#?e>6|U?P!268rT$+ zRV@@RcW(-y`^l`%UQSMk&`xRH4zUkkgy*(9q1D!rQU3LSI8u>t?7lHqKiiHUjYl(! zl0^=>Urz$YHkh$`94;ArwOf-(#b=J=AGO~aN_Xz_nWi=9O#a-w0O-2}P`8sBa>Tx+5Z}OB~5OEkJJVg`ltDo1zNA!8K zM6&%&Pry;0`$)kz3rK2InNQK$%@F=CAPUQ7?G+2ONWeWoqBaMCQ(*A@ln}{K#OyrX zi!8c9dsxDEpewSZB6gC1h#wCg*M)yf}NlPh1#kK%OT7qDvPg~<%7dzMGHoKt10fC_D=AS*$_rojc ziJj^eYZcKFPMIIB{Y0VtnK|YVsMj+8-W4=j_INzW?$ht4c+&^`t=G^@q)A=vBXYml<3~)ktHq9yuTc~YvuM%DuY-FUJm(w4;gpBdV)9?EQ++8|ZpVD4~n~w-R{BZej z+8s~k3l_#x#*G)dt(TL3C`%^c2mM(@8%WCCDib#@kzDj1iDzaLv@|phXWfpTLbTXi zyyZNc!`#EFeO&pCyr|RBhyid@a)CTW!3d5qyd-YzT~zKy7zPYKcL@C^^>c_KIsi|E zHHU0Smv@W(M^(9Cgb-!7%MR9cRH1?E8#C%1qoAC9n=>9Nn+crk#R-#%J=6uB92QZ>w*~=i4V;Fwgyp#Q|Ie%Z)fwGJ` zd~$eM;-dK{(x`aY%JthC_|I+K-B{1)TK13APcBP$&mt$zcMX2hY7WX#M@ODX@R3e_ z(ixv96w60LX7I$NcI$w*#L*O2{7G18jeK&K^S)X04||nB-50!|R$!MQnWbtr=%9)j z9`Yp$oktIlYTvE}LVo;FXecZ3nXPsF2{@8ut+m;O6cA$02Ekx(J|B8YiE^yCPfhRt zxny&K)EY2mKj$J28WIA$o!7z0ooi<+(GpEEX!5}x5Q_B+_y^5U&C;e`nU48NEO2t@ zRfiQVAo^|q`krZ5{z0K>a^ARkjFxcq$J)=N7m7uPhJbZ}AMZ#FN8bsE9{ZbaY1m@!hB1tQ-1(TY)}~>_kAHnk`|Z;V zLs-BD(-m-H@POA6w#vHJ{pb?4BFDMiSr2>8_GI}U58HJ=R|AJJX9Se!i!`vRYI*(i zPANK&&d6)pGVjIh`S5GSXCQD1d#jy5gb|3rRVrB7`BeZLJ(2tUstku#{Nb3rS7GfC z{agor=HhwGpZ5b_qy!eckEHR~lqYC{8H_o0p0MK%mxeA74Gw;F#sJ-i6xtqaOf+wk zVw;HDZxPK~r}kS8-#>LTGWR!8T8g!{CAW22{QZ-QOoCw7>#8AaMG_CS+1g8t6`!`0 zwJ7OV1|@R(GkWP#zxG@aTCKPM>~yxf_VRnq^Rl!arV0*8fRm8mHz0cMDok6x60$sR zQ!&U$j((_;f$B2A+ugC2^Q6YB3*{oib332yr98!Q6Cj?+P8#}rI6j@RXYoF~$1UpC z&!6DC&7nyzW|RzWG`2 z=zYz;EEx9Aua99QG)?#J@&q&Gwoc^jukp_Nh+CML%{@vZ_3mCL@8!$}?t1Ck@(6 zcl7Bg)?seDmWk{EVNUG-tV#9)x7+y%=#Gn;Y0vvcX?G|6Zi|<2T9*sJ+35~=EToU4 zjItW>YdI=_lE)iQR6p4|5&;q5`tI1szqr5j%79W zUE2Mk2x)&&bjke{OH||vc#rEI-AAD&%yg=N6H4S05!&x^9J-=Qfy9glor!e#CZkvE zr7-_Z_&82R*rz!v5E(moG{P@Av1X?28>1*)Ahok!@yhbTxyPTEAe=#pR2EH*M$bV| z^?IP^#w3d=sY4anCaW9DNxc)<49XtN+Vw9S{}?EtQpO%Vi3&L>^=uSuhu_0ZQ?44K z8)Y$C-Pf2k(TISpy?T8Hr6a^>v-ja=HFSjQ zm@_zgWuhU6a;wb(nL}#VzqTtseqrmG8V+Xyt0c)59~=Y%{^r88SyDct8E$TYxa)_^ z>~TKzM`G0L?qd^?Vp~weu2z_F?Uu6Z7;u8{h@_s-;D4lzd)1#zXeaG34Kvw@@_R~M zQomg=t8tGBIknHRlEdwF`Q`=@F}FuZt0;wXY7$u&jyOTc8@uy3e&q*Iud8IE!p%e)yp=^Gk=xHN)Y{D|qPly+q}1-TUKQ z!p|Z2w3BUf5t2+!2DxHdcLg<(;PNoB_ZYR8^m#hH{>?gD)r&SgrMKlry^ylzjIY6} zyJ@=B3%n@TNkvN)T)!cDL<(sP#yib^Sk$D+GS2OQN#^4#S*tG4jw}k^7NPPWmjhYA-P=bwDCE zJ|meO)s43?tIf0^w5=g>9|Uv7=4jt~;O7egL-}7&>U|)0^XCn8TGOO=yAZBh1B`iK z<)?;;$kCcWj%M@}Kb38(UBfv9$XP0eC(^9$qokJxtq1dn7&L|WONy^0ym^f!NjVF8 zw&Q*f{fA)zq{zix7ryO$u79SO?Jd(BLNNMuGTfIj-_{+Af#Vp8Yqx5&TMH914DC4>HYT{<2pO|CQLRm8_IoM=xK?4!{YRxHQP^1;xPg@ z`44`pbxZ9S9cBECjicrfPxY$=#SAl8!1wBf}ky!*}_^ZQ% zo3GB-VjDD1IxeIk26k~(kbxi9gj561LYA%Flmn6imJiR;46)s~kt2JAt0KzXb_|g!c6T!3Lj{WOS4E&s6Q3OLEKKeNG=02 z3K}Kv7Ot7x^aN^+2a}fNbsFny!V%l|1f@H~G~5J_!h1VE?<>N)O#~EIUh`2nd@oB= zoADj8>=Ah(uAQgT>-l404x}8QP!ut(|GVL&bW7kTPB#i2;dOKBuHI<3#W-fv{M^Pw z4UsG|WD&oDS=$m?b%rT_t%R>EDgt8Wk~dfCG=HNHyB@ftMQ?Lx+QXObO~8}x1+Y?7 zeClzyx(P}F{V#A7Gpj+Jf^w;YWG8{`&GKM!Wv*ukjjP-ss~(Wf$cqfbjdXf+Qtoij z8sQWHp$8_e!J~vkfkPsFXh;BqN?e=_PBeGBN!LgD!w(?AiJP2d^+RG3%zNuGqbh60 zUICCL3(C9~koSX)o?n(SYr)+k+=tABG#r0 z0drdnw7UngO3J--p9FS~N|VFBG|#L>=gmu@xixLxu8IlcxmWjf8FF7OAHG})@;Q!w z*PqQDvH1NJC3NAgB>F2qRQGC*_S?pl%;9-4=NBABZ|VX@o%Z#SRo6}os$ zsJ(jH16xY6=>kEAG>IRaw;-bymJlTh*~*lt>%BRxY0k+U8iootqyEID7UF@r0tKD0 zkGBo=X$9NR@O-E7P@y1f4sZn5Sr^C*y?=6o<$HZjT8G|=7F6=A- ze`xrrkOa>XjA`+c*4wZ^^W=LQG;lLos6cjbt{dens1`0>-wW0S)fl2btP(~C!2IyZ zr@OpN==9PVun>?hU1?ZA|1^^5;)}6}Vs_+JGz)5IbQ>WXx1k1SJBD|Zt>^#LeoGAh4<9HN@X{P(zgE)P4cq zGjW0WtuG6@YtWNILt&vibQ&c4YN7^gZwO(ha* zz~eytp2{qa9Ou?t({}@0M_d5C*X_@B9wWO12tg!=xMiKemj3~S9I+A;(_c7NYcFyf z_9X6(B+@fg)rpl-1qL|*F&*B(2vtWuEd$|wkHmidz3kM4qt&+9JKvOxHE`}=ZpPZ0FNEZDXkXXK zy6A@tjGB!d_mg-lQjDU1SzzzJuES1Ig>u?H5NdiTYGmNefLVcyZrg$27ZX#doFXBBjOxOd z$q}mOEFjM=@qPPOSzY*V-8s9sP#rY_D0T5vp{|%ZSW*Ikn5k6Rn(?DvqWnW=eJZip z%{mckp>VS9DNtBPx{nn9{yvG9DFPde{I?Ja3uiv>lOh00%|6>T9@I-r&^Ks-Eqfuu z2;F}`r)+&KHufk4=mZn$$^gA#1@dn8f6DevtAD-M*PrY1E=7!c<7+#1U`L?>o;iDC ztE-LccPsf145iy`Q_u!wo%=P*oxBJMwj=;6^^iLM%Dgq1{`G!)TVUM_;LEMMiB7u0 zIDSwB)SYQH(`SWojQ(#BZ{Lw=^o28lcad^O{jdPN!9sqtfyH{-0|vdG@?Y;YHEVbm z*b$RfnlRI6jB!j1p1Dz*(a?~}`oDqQe#j!Ay77O#udlC{QeE1#B@+%`7+{N2pK96t^4}>_SPYX|J9tA{L{bx93QtGI0ML_{|x(D zwG%n=O(1|SCB~~0#|bw7KfQ#i?zj>D{C9VUREeVhHRRvb$DGw@zs;;HjCt5!rT6=G zI)=Z5Q!#0IdA_`Kt^T!LHDhIuawx~cFaaGBwy&>}VocdyD9Ghhvg~HuT@1~nL5Dqt zj$p&b;{Do9M;EYtP@GLmUhv+yHedHz7vx(bih9%LvOBGA=(0Df9r#$i8T#P^!p--a zg8=~&<11Ix?`~$@F>C~WSxk~*_@20`;*650HiTuilYO!7Q_ly^rRmQwrXJhvJv0iJ z_QhDGLfZCdA~e4QKa)@*&A3K(WRLK7T!;GNBUgv-#G?j;-Xp{iLLNKv)g=l4w zq6-WfJ)uuHj0&g(Y)0zT3)J#`>w?+Ybvto2w^%s|>5(OUJq^;%d~d8B9V|-Vk}cKx zOmK`AFJ9Z}r!GJxUDz2x#v*?N(B=Z5yZqkt;i^EV$|@fqv>M|@+I(!vU%2Rj9l@V3 zuJaz?V@%I-@kBQ1Z(i=tH;#iSH1+TrcwrZ4lp5@IDTWaQ+|%uhL}KP(Bn+hnYo|?< z?Mm~sG{|RXIWgO%;nP7amwr9-!G_Dp_PF9=G*=DAHNd*VL|nF+(W62o=DQ_p52@+G^}}oR>#vW)H<5HJy>kLY?3OE+w0u* z_av*KwD4F7y>|jDs~WmZys>kT!N z1*^*y$M$v12b?QSs#WqN4AW>|+lDR*{GhVDW-_m)@LQ8KO)+GVie zU!Y2g_h>hHd#KkrnQ^kTrJc}hgO5}=TL|wp-$7jf0{Qrl@BO;#S@1W<098Ei6SrZB zJxa3_zL*-f=UGHFPXOIv>Fb>EC;|I>*NHJz3)XS;~N;C&05+Eq<MR$pbn*171FZ zekB@MMcBxP0RaP$;9*f|A>e$7$OYB!&htS(4Wp|2VqGDo@@_kib(z5qiOFUJH|I%znCry zN<{GV*tU`_lp*krKtA`_pQD#+l+hVtUfb?Z2EJKB8`nBev;y}&d*vkNfvf>D$xu(8~D1(fSsEw-c| zd=8f7Dou>yvT+9dR)mkla|8-3-c1MkAr_P-p%O+dzLmpM1o&)u+Kc8=5Fo;=kq$t^ z{nhu@)NM#izQtKaL>}@I_OhAPr#p&^1QH3ssr$2gc@5e*G!_1$=*lQ(u>)pMqbNZKDPA^8B}feMjkN+x;w%kY*67-BA{ zD&;XNd`|ANwrFHKa(t9Lh23M{gAHFbMT~C&cSS}yN_U->ziW*y^KMWPzhFjsyT~!` ziY|HnD+&p}sp}S4kLsZE-Gd8|J4te*kG^vtoaDt;5E>oC6z*wRoaNnB5L(y3-1ze` z&}2HN-!3D`gMJA3ug_7SbZku&r+(T8iNydVEn6PNs*$cy0&xYwqy35@5ycP&6~2-7 zB=YXc{>XsZ77W*|7@vX9yz&BRm9?v{BxO3Vmj2E5d6w2yy5L%4i)-=97)rB5?A4b}Z7-Z9_d@2q;)A zaNwr%@L>KzxW^A4?H4lv9V@{eON1dMMgSYLsr0;za^N!-K%=Cn`NPADN*kIq#E=f` zK6da4&v|^ET5NdZ`OX<6R-m^R8y(=J&l*M2fNl_RYL!Wvgn9d_i=@3wF}{k7TG zdN=p>E(PW%%X>LlRz++aKUu9G!3l3kBIo|^RD)eM6sdf+p=#JAb*x|+A{keqk%M|S26BoTKV<#V>|7`@S}>#o7`PD-i5o`O<_b7 zAv5eh(oCs+o{G36;i|8^_+jc@RWTdp`E9k zo>HCWj(5=xV@T(_AWLzVYx9SJKst6oaPT7C1%iy2Zl^vIsI%KWR{n3tZ;uG+nun^N%VUvKOZ!Hgj(<-1^N%JiN;pSNbqb8F%1 z-)m&aZ088poPRkfqfCTvZ;QH;QoT@lgV#4*@Z37k7G3|{g;S!TKu5rhwQIoPOBco~ zd3!o=BM>{mk`(_l4y;P|lVl(V{;g`39ifDn9fMEb-JP#Q$Io}u6X5sE)H<$6$3Ie1 zxM`=v|D$zZb~#op(XTdZ_iVx{YuD}CrrB0>v)Ep-*87j)jl{chpPPZR7emr<-gHJr zS%{MwO#9cT_xgg}dum9SQ7e$O?);KTJM zxr1mi^T}N}LDI(Ifj_RC3&C&@~ zdB_t6jWn;{pN$-B)p=g>WF4s*>Z-rvEZfb(<}~CwGP%?7e{?ljy?4$yNB%r20QShF z&YLA!1NygfN|0Cg&z}U8mXQ-I;X?yS`{aX;-YD=LEIe5DYdjsaLCa97;UhVP3kG=G zi#rwm*2`RBP>B|p`Aj*>5D$S6q-%+6h+)qCF?g{Yi}zzW$U+K2z_P%V>1koQG5t8l zLhWW~=blWiZU3>V)WjPSH0ElWN{^(r%l_LcQ!%ouNup7{W?sDc-S1l-S|=``+6M+) z1yW7AsVBxlI;6s;wDIR5s?(!ZYg#kYql_RpaO1rg@?3oSUh0*@D_T5CKE$oQ*9iOp zQx`#emNxI#j$oiw&eYgvGNwW#2@Z`Xx^^UU2Q=zKncU79;Rj#UudNBZj!JT_UZi<9 zcyFgCq+1tSUC@$Xe0(_*eAZIBD@CoXGJlG4*1m2dx>=UU{qC^utb3n^Z=e2Z^4(eK zGcWG!N70DYuevHopNY#99(;ez$v5N~0HB*ol;Rx1%Y<16JK(fYEEW$5&>IZ(0WY>h z_>JX(86)i>?Jv8LEWeC3pu$@5#d}L!>mqPLHeht30A&A+J{zElTu}(7!rtIldv%tu1 z9hpP`Hx#$a@z;CpTcLA#$a9VUIxF%uj-bGMJ0joe5*8$f1FI}YADQVI>=&Ude~s;R zJ`EW#jKkhQyqX5p;veM4!8s5_KbtvFu|SY==p}xVN&zws#ZqN()b-| zSj4)S9&4ohuuUiXetUGWiV}6Rll#hy!OY_l+skJWDl_)e(9~*N&%_e3Sd?yWg4^di zFJ_NnBj=uACFtyhUw#4jNUNOumZ#TMNYA^_yR?YSd?6k#hOA^&u56WKH6PD_#*{ zy_YOqnJ%cBwjl~^i^%NgGkUokD>qiCsd6Xpy@^kU{Kv3e(;}hv55`oKp&X3?evb%%eZQ5lLYmO z=N~~rqk(7UVq>E}S!J!c>*ku_*uI!=*xb~VAz-WXT8JAIOISsb#~R8_$X7`oa2ph9 z6zk-qQ4pzrd46BL!d$5eux}C`msbQ!3#Te9qQn+}grWdElRrEqEjcaoXk$@kL6)KY z`r@dHnv`8b4UymjW?qAn^5?V2;g(~JSHq(w?V_Mq6G;5GSi_Wd@-m+(7?fdTiq1Lk z2t)6KbX!Y}4_hAfZ4hX#%rar&WIzz^V^GbZ8gqKZ1^V#|)L>MiarZ&Jh(H;Us}e;! zOz`DIkt3e@v0Nb}P5%JA$V7FJgPAat6uEkrGEBC}0RMr&cSPmrRsXX(&`-JOdnXVv z0hkmh_Xz!~)OR3UmygY;L7j4{@z-#6-Ho+^2YcbHU-*4+MprcXDn4_VSG;2M-UhZU@)X}F;s&^;?flI*3)i19Ve&@H4N}_;*z%ldYzkQ(YGTPi_mn z$$hDcU?z2)!zlC+@3WhG^@K5o9r3>BNc zvo$%~Z6#8$ATPsHLG}XBILDCCsk4B5ee()KSu7Wu3z<3wwZ@K>g0P1a44EE-wt@)l zGOt%F_jZ;>(ssynhL_*A<6LCUS?Tb}E0sog3Us|;9%T&4YcEH@Zhke@F;OA$LpwI9 z+_Ea`w`6=U%%Lq_F>=gf^JavBZDfd@y9#o zAGNf=7_f27JNDWhtq)@DD%Lrzsa+hdt-Suz@+scaAgh3|L+Y$FTH?C_<(aESvd{0M z`&A}YR#ta~+2CJ9$$Ah)yEc{3%pn$QNl_TFQKXTBZTB))A9 zULe;gupG_Rju7!UG#zjD@o}qWN=2vpaIESA41T^zBRG}g089D`wp)smy)N=Zv2Gro z@G1fLgi>zNIVp85?>=;q{;Z_C4Kg zXx>0#n9(c|aspxh+(#=<5Y3zU;cJTPUW`jheCB4(WwYQ!`fks9tE_I7Mvb0>vBH=p zOH-csg==tuPX6n@Mq5m+8pi;URqm^Togs0-Ew~V2bmWde0lJF&tHC?Zrh+=agq<8~ zP^(HAk2}EF>1?CG9>??glU1-w{pT>oJ@5o~hOy@9kLM$ygiMunY7q}OXX6me`;z9k zQQr?hEwByhD3it(=`Np;^UpzTZ5*%~^V-X%sE2`X^fSYi2>iA(*Nz>XYMcDa)7>3h zu2FuuF>q}UaTh&cb&`CG^dQ?j=$=3U!rke_lXp{MA}}c3y-24@p)_D;wyq-Osbw7C zeW_|_p*|!!fl2cJ2y&MrW?zLY?|F@PDW$4Kpx4*>!_Hb(N}6AHhHtmq=jP8C{>f<{ z64}M^7_Pr!q?dq;dvnsk! zfBlR(6Entrm3R)4hg*IC$ZkrU1~9FSr_gKnaZoedMfgCDolF{*-hdiswbie0VW<7~ z*T`SK%oNw(1-6ryv=4Gk{6zGs)19tPcS#SQ>?j_$n_ats(X}2e*{xn7c~||)NivS} z^~WSmWT!5s#~o5o)(gOT8B>*|N#vyV3zZe)e#I};fnvI3UsI(Tp~*3s9Oc&Ye5IYz z>h8UXf#&3y_sgq=z0*)Dr&Zo*ZnA^`qnAF_nbWr2>BnLmFT0UlYUSrLRU`3=3vZHd zt9+KUPi8+0jy>~{zu8RMs(X2cSNb7KU^ni@IxRFL4IYXGcfVNRE|lk1{xuHmW^wy| z6E({{%Kqxui<$OCslP3m(fUAgfp&#CqNw&t%A8Yb>9{S%yXZG;pp9qtQb??FD zmxH{$@wDKANkPnSuj8#I)?828OR?34cV_abhJ+VB$efkZ*lW;v-vm|Y+bQuk4AVFE zkB|MX7>gA&C|m)r@pYk^D2$(8_%5D$Qe4p3ZIF_nR;)MsVl7vanYL9x>B&jL-r2Zo zX~9`0)NtVuoPc$_)X>ln6sVK}f9YzV3J8x@5wj?(0Ux@+43W-CPQ4&3Qj!U$kCglh zOY94Vw})hnl9lD7BTIkq2Hv$)VnxVCwu=o!84Y%kYU+IfwmsbHjh-$UaN~Pe2i#$@ zzU(aDzQ($vmM(waxL**@nX8eSrvLqs@|_Ni>J@#S&zy4Vi)a2=Lo(R$&8hh^N*UjD zGJdPwm?h~eUTSuaS+)MkvHCTzwGET;d6Sxs@7tyBy4QGfVcKZE5D8J19C4uIP`1d6IyeQ9}NkPS^<9e zxKp-$Hg1vEyeRdc;;KIQ8<7-?ueSN~`7YEiTTB7Y>Q=KfCUMZ|l{k zgAB~@xB@VGB18Zc>jWK(Ni)~5h)PQ2Xk&QtXN-jFq$qGp9u+s|krY;aBxKYGqQanS z)vjOW=6>jXUf|aYK}NFklxM{Y_@`|~bAOi|Lk9=gcBt;{Gdv??^g300sNL>#6<0OX z5eMx%dJk%RQZx9zBn2bp-BLvYW z))PCTq>nXUt+6Nkd3)Bc+5FwCnd1%VWA#_+Zbb#Ib3U5tCW3c-ZDqO%^4Y&m6K9`7 zezQ@ODnve(-=&-|%F=JQdqY~NHWtm5TJw@Kxk1`ir&(UTKtq1lV>1H`js}-r{(}Ln zEFzyzf7)ug?{>eCMSC5crs&M^9nq@0gcNuVb{}5!S8-^i>F+G+6eyhhi6We;G>+G~ zzIj{qwiPR#W;#Uwwmzc3#b~>phAF!B-dd4fvFSRtR;dn5fg5k3Vko2F_4q(4mW^Js zYSLL}p@Etq>@-NZeol0E45^zgizt;C>m>A2l9ot?2?ff4&f^y_`(03?#<=(mw{F=< zgb9z<#ZF(G`;0L8pN(jwun@X725c#d(Du8-XOOmcQ3U1N{b9A#F{`LuMMSYwA~2we z^t>4Zd^@+st9U^_>ykPdF>u|bg!Xtzh2W{1qlC^kdKFria`FzxI4&l^S3ga>-r%lV zB^qz^avRT8qH=r1Ia&uk_^KX)N8_A#2uciBd&(gdKD6$ONNz^a8xP_4!YGBEzSRSJ z@3GCF*=C2+3pt8pjmG!U4z^|y{=623gDFob@FS-D%s`3Gtn5?~NBnY=iQi#S@~{7Q zCrT_blKci5F6B3_#>!P{H2XC0jS$t;d;@3I-qSqr1)x+l}pFMPw_8w%&K{9j2LLdPNkiZ@phoLg(5@=`ktC zZ~L-xcDwVxa*ZtrjugGi3oZen2w)e-3@-gyPomePS{aV{lK-GO(${miEsQq zzCldf*tO-6dQI@0vwJ;1cdDSBMs(V7=%r&{G#mEe&yo)!i*LsFQ=n{?O!vt34hJ4u zEij$B?8m#;z6zWPC=ErFUlcYqiM%`8lZ0?yAG{#3fIhXE;@N7Egh`U7ZyC)Bit5F> zpMRl%@!-i}X|lw*o5r)7qdK@oT|brp501k;-rt-9lk#E&u$8J-?;huVF20G0YMCtR zR)UNvzhM*?=6=3?pCwGT-ojJ}ZFZ$A^1X%OfY|2%|8rm8#C0Aj$JYD3>De7E`yMz4 ze)}0-x%*kqG`Jf6JZbJG4MmrWPIh_r!FUw6GU!(?t|)=HSs#g8V_F!?0&Zm$J>}=0 zEp|G9I9C6N`H@|{p*&Bc}_ZTI)^G@m`Boj<(L--jOTZ4a@zJ^GNCDdJtQ{Xx~9 z=4LsMOM~TZ!?ame{lDFW4KQ#j`sfwRdmeBOrxz!&=)L!U4jCb6(dq z#j;_I?D^7y_|TC9U1lal4(vtE>*C>ED%X*%pP3&%=;Bn7R-=uy{{MYg%gVD1_y?K^-^@ z0|DVrdOzkEkQehp=sXn~0oixYwzixGZPmzA7ZxIH+79AGMo%H4Gsaq|mWvC_{u6%a zzQ-*U8z4uc8gsWEu}DK(;|zz?&->A|nB{`_&=&AjoXe$VLZ%2e9q9R4JB`V(!y6nU zI)RXSA+pLb3uS|C1iUvBwVdCk{ui_g3YvTVCRq3nV)7 zK^dS%%RE9 zx~+PB$42})*SRsQq3BxG&N_qYraaw0Z#?m`i=_v~<#Z-wMo7y;d- hZiVM@Yc{ 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 E1MCXXc>n+a literal 0 HcmV?d00001 diff --git a/vendor/github.com/documize/html-diff/fuzz.go b/vendor/github.com/documize/html-diff/fuzz.go new file mode 100644 index 00000000..da021b3b --- /dev/null +++ b/vendor/github.com/documize/html-diff/fuzz.go @@ -0,0 +1,212 @@ +// +build gofuzz + +package htmldiff + +import ( + "strings" + "unicode/utf8" + + "golang.org/x/net/html" +) + +type fuzzCfg struct { + cfg *Config + cmp []string +} + +func baseFuzzCfg() *fuzzCfg { + return &fuzzCfg{ + cfg: &Config{ + Granularity: 0, + InsertedSpan: []html.Attribute{{Key: "style", Val: "background-color: palegreen; text-decoration: underline;"}}, + DeletedSpan: []html.Attribute{{Key: "style", Val: "background-color: lightpink; text-decoration: line-through;"}}, + ReplacedSpan: []html.Attribute{{Key: "style", Val: "background-color: lightskyblue; text-decoration: overline;"}}, + CleanTags: nil, + }, + } +} + +type fuzzer func(*fuzzCfg, []byte, uint) + +var fuzzers = []fuzzer{fuz0, fuz1, fuz2, fuz3, fuz4, fuz5, fuz6 /*, fuz7 */} + +// Fuzz is the test function for https://github.com/dvyukov/go-fuzz +func Fuzz(data []byte) int { + fcfg := baseFuzzCfg() + seed := uint1(&data) + fuzzers[int(seed)%len(fuzzers)](fcfg, data, seed/uint(len(fuzzers))) + if _, err := fcfg.cfg.HTMLdiff(fcfg.cmp); err != nil { + return 0 + } + return 1 +} + +func fuz0(fcfg *fuzzCfg, data []byte, seed uint) { + raw := string(data) + var x0, x1 string + for i, r := range raw { + if r != utf8.RuneError { + x0 += string(r) + switch i % 4 { + case 0: + case 1: + x1 += string(r) + x1 += string(r) + default: + x1 += string(r) + } + } + } + fcfg.cmp = []string{x0, x1} +} + +func fuz1(fcfg *fuzzCfg, data []byte, seed uint) { + fcfg.cfg.Granularity = int(seed) + fcfg.cmp = []string{string(data), strings.ToUpper(string(data))} +} + +func fuz2(fcfg *fuzzCfg, data []byte, seed uint) { + fcfg.cfg.Granularity = int(seed) + for ct := int(seed) / 2; ct > 0; ct-- { + fcfg.cfg.CleanTags = append(fcfg.cfg.CleanTags, str5(&data)) + } + n := int(seed) + 1 + h := make([]string, 0, n) + xx := "" + l := len(data) / int(n) + for n--; n >= 0; n-- { + x := strMax(&data, l) + h = append(h, x) + if len(x) > 0 { + xx = x + } + } + fcfg.cmp = append([]string{xx}, h...) +} + +func fuz3(fcfg *fuzzCfg, data []byte, seed uint) { + fcfg.cfg.Granularity = int(seed) + raw := string(data) + var x0, x1 string + for i, r := range raw { + if r != utf8.RuneError { + x0 += string(r) + switch i % 2 { + case 0: + x0 += string(r) + case 1: + x1 += string(r) + } + } + } + fcfg.cmp = []string{x0, x1} +} + +func fuz4(fcfg *fuzzCfg, data []byte, seed uint) { + raw := string(data) + x, y := "", "" + for _, r := range raw { + if r != utf8.RuneError { + x += string(r) + y = string(r) + y + } + } + fcfg.cfg.Granularity = len(x) % int(seed+1) + fcfg.cmp = []string{x, y} +} + +func fuz5(fcfg *fuzzCfg, data []byte, seed uint) { + raw := string(data) + x := "" + for _, r := range raw { + if r != utf8.RuneError { + x += string(r) + } + } + fcfg.cfg.Granularity = len(x) % int(seed+1) + fcfg.cmp = []string{x, strings.ToLower(x)} +} + +func fuz6(fcfg *fuzzCfg, data []byte, seed uint) { + raw := string(data) + x := "" + for _, r := range raw { + if r != utf8.RuneError { + x += string(r) + } + } + fcfg.cmp = []string{x, strings.ToTitle(x)} +} + +/* file decode time is too long +func fuz7(fcfg *fuzzCfg, data []byte, seed uint) { + dir := ".." + string(os.PathSeparator) + "testin" // should be running in the fuzz directory + files, err := ioutil.ReadDir(dir) + if err != nil { + return + } +tryAgain: + file := files[int(seed)%len(files)] + baseHTML := "" + fn := file.Name() + var dat []byte + if !strings.HasSuffix(fn, ".html") || fn == "google.html" { + seed++ + goto tryAgain + } + ffn := dir + string(os.PathSeparator) + fn + dat, err = ioutil.ReadFile(ffn) + if err != nil { + return + } + baseHTML = string(dat) + + ptr := (int(seed) + len(dat)/2) % len(dat) + dat[ptr] = byte(seed) & 0x7f + for x, xx := range dat { + ptr = (ptr + x + int(xx)) % len(dat) + dat[ptr] = xx & 0x7f + } + fcfg.cmp = []string{baseHTML, string(dat)} +} +*/ + +func uint1(data *[]byte) uint { + if len(*data) < 1 { + return 0 + } + r := (*data)[0] + *data = (*data)[1:] + return uint(r) +} + +func str5(data *[]byte) string { + if len(*data) < 1 { + return "" + } + l := int((*data)[0])%5 + 1 + if len(*data) <= l { + return "" + } + raw := string((*data)[1 : l+1]) + *data = (*data)[l:] + s := "" + for _, r := range raw { + if r != utf8.RuneError { + s += string(r) + } + } + return s +} + +var tags = []string{"u", "p", "i", "b", "div"} + +func strMax(data *[]byte, limit int) string { + s := "" + for max := limit; len(s) < limit && max > 0; max-- { + txt := str5(data) + tag := tags[uint1(data)%uint(len(tags))] + s += "<" + tag + ">" + txt + "" + } + return s +} diff --git a/vendor/github.com/documize/html-diff/htmldiff.go b/vendor/github.com/documize/html-diff/htmldiff.go new file mode 100644 index 00000000..2f7965fa --- /dev/null +++ b/vendor/github.com/documize/html-diff/htmldiff.go @@ -0,0 +1,193 @@ +package htmldiff + +import ( + "bytes" + "errors" + "strings" + "time" + + "github.com/mb0/diff" + + "golang.org/x/net/html" +) + +// Attribute exists so that this package does not export html.Attribute, to allow vendoring of "golang.org/x/net/html". +type Attribute struct { + Namespace, Key, Val string +} + +// return the "golang.org/x/net/html" version of a slice of Attribute +func convertAttributes(atts []Attribute) []html.Attribute { + ret := make([]html.Attribute, 0, len(atts)) + for _, a := range atts { + ret = append(ret, html.Attribute{ + Namespace: a.Namespace, + Key: a.Key, + Val: a.Val, + }) + } + return ret +} + +// Config describes the way that HTMLdiff works. +type Config struct { + Granularity int // how many letters to put together for a change, if possible + InsertedSpan, DeletedSpan, ReplacedSpan []Attribute // the attributes for the span tags wrapping changes + CleanTags []string // HTML tags to clean from the input +} + +// HTMLdiff finds all the differences in the versions of HTML snippits, +// versions[0] is the original, all other versions are the edits to be compared. +// The resulting merged HTML snippits are as many as there are edits to compare. +func (c *Config) HTMLdiff(versions []string) ([]string, error) { + if len(versions) < 2 { + return nil, errors.New("there must be at least two versions to diff, the 0th element is the base") + } + parallelErrors := make(chan error, len(versions)) + sourceTrees := make([]*html.Node, len(versions)) + sourceTreeRunes := make([]*[]treeRune, len(versions)) + firstLeaves := make([]int, len(versions)) + for v, vv := range versions { + go func(v int, vv string) { + var err error + sourceTrees[v], err = html.Parse(strings.NewReader(vv)) + if err == nil { + tr := make([]treeRune, 0, c.clean(sourceTrees[v])) + sourceTreeRunes[v] = &tr + renderTreeRunes(sourceTrees[v], &tr) + leaf1, ok := firstLeaf(findBody(sourceTrees[v])) + if leaf1 == nil || !ok { + firstLeaves[v] = 0 // could be wrong, but correct for simple examples + } else { + for x, y := range tr { + if y.leaf == leaf1 { + firstLeaves[v] = x + break + } + } + } + } + parallelErrors <- err + }(v, vv) + } + for range versions { + if err := <-parallelErrors; err != nil { + return nil, err + } + } + + // now all the input trees are buit, we can do the merge + mergedHTMLs := make([]string, len(versions)-1) + + for m := range mergedHTMLs { + go func(m int) { + treeRuneLimit := 250000 // from initial testing + if len(*sourceTreeRunes[0]) > treeRuneLimit || len(*sourceTreeRunes[m+1]) > treeRuneLimit { + parallelErrors <- errors.New("input data too large") + return + } + dd := diffData{a: sourceTreeRunes[0], b: sourceTreeRunes[m+1]} + var changes []diff.Change + ch := make(chan []diff.Change) + go func(ch chan []diff.Change) { + ch <- diff.Diff(len(*sourceTreeRunes[0]), len(*sourceTreeRunes[m+1]), dd) + }(ch) + to := time.After(time.Second * 3) + select { + case <-to: + parallelErrors <- errors.New("diff.Diff() took too long") + go func(ch chan []diff.Change) { + <-ch // make sure the timed-out diff cleans-up + }(ch) + return + case changes = <-ch: + // we have the diff + go func(to <-chan time.Time) { + <-to // make sure we don't leak the timer goroutine + }(to) + } + changes = granular(c.Granularity, dd, changes) + mergedTree, err := c.walkChanges(changes, sourceTreeRunes[0], sourceTreeRunes[m+1], firstLeaves[0], firstLeaves[m+1]) + if err != nil { + parallelErrors <- err + return + } + var mergedHTMLbuff bytes.Buffer + err = html.Render(&mergedHTMLbuff, mergedTree) + if err != nil { + parallelErrors <- err + return + } + mergedHTML := mergedHTMLbuff.Bytes() + pfx := []byte("") + sfx := []byte("") + if bytes.HasPrefix(mergedHTML, pfx) && bytes.HasSuffix(mergedHTML, sfx) { + mergedHTML = bytes.TrimSuffix(bytes.TrimPrefix(mergedHTML, pfx), sfx) + mergedHTMLs[m] = string(mergedHTML) + parallelErrors <- nil + return + } + parallelErrors <- errors.New("correct render wrapper HTML not found: " + string(mergedHTML)) + }(m) + } + for range mergedHTMLs { + if err := <-parallelErrors; err != nil { + return nil, err + } + } + return mergedHTMLs, nil +} + +// walkChanges goes through the changes identified by diff, identifies where a change is a repacement, +// then appends the changes to the output set. Once that set is complete, after ctx.flush(), +// they are finally resorted (to re-order those in containers) and written out using ctx.sortAndWrite(). +func (c *Config) walkChanges(changes []diff.Change, ap, bp *[]treeRune, aIdx, bIdx int) (*html.Node, error) { + mergedTree, err := html.Parse(strings.NewReader("")) + if err != nil { + return nil, err + } + a := *ap + b := *bp + ctx := &appendContext{c: c, target: mergedTree} + for _, change := range changes { + for aIdx < change.A && bIdx < change.B { + ctx.append('=', a, aIdx) + aIdx++ + bIdx++ + } + if change.Del == change.Ins && change.Del > 0 { + for i := 0; i < change.Del; i++ { + if aIdx+i >= len(a) || bIdx+i >= len(b) { + goto textDifferent // defensive after fuzz testing + } + if a[aIdx+i].letter != b[bIdx+i].letter { + goto textDifferent + } + } + for i := 0; i < change.Del; i++ { + ctx.append('~', b, bIdx) + aIdx++ + bIdx++ + } + goto textSame + } + textDifferent: + for i := 0; i < change.Del; i++ { + ctx.append('-', a, aIdx) + aIdx++ + } + for i := 0; i < change.Ins; i++ { + ctx.append('+', b, bIdx) + bIdx++ + } + textSame: + } + for aIdx < len(a) && bIdx < len(b) { + ctx.append('=', a, aIdx) + aIdx++ + bIdx++ + } + ctx.flush() + ctx.sortAndWrite() + return mergedTree, nil +} diff --git a/vendor/github.com/documize/html-diff/htmldiff_test.go b/vendor/github.com/documize/html-diff/htmldiff_test.go new file mode 100644 index 00000000..751aeaf1 --- /dev/null +++ b/vendor/github.com/documize/html-diff/htmldiff_test.go @@ -0,0 +1,369 @@ +package htmldiff_test + +import ( + "fmt" + "io/ioutil" + "os" + "runtime" + "strings" + "testing" + "time" + + "github.com/documize/html-diff" +) + +var cfg = &htmldiff.Config{ + Granularity: 6, + InsertedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: palegreen; text-decoration: underline;"}}, + DeletedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightpink; text-decoration: line-through;"}}, + ReplacedSpan: []htmldiff.Attribute{{Key: "style", Val: "background-color: lightskyblue; text-decoration: overline;"}}, + CleanTags: []string{"documize"}, +} + +type simpleTest struct { + versions, diffs []string +} + +var simpleTests = []simpleTest{ + + {[]string{"chinese中文", `chinese中文`, "中文", "chinese"}, + []string{"chinese中文", + `chinese中文`, + `chinese中文`}}, + + {[]string{"hElLo is that documize!", "Hello is that Documize?"}, + []string{`hEHellLo is that dDocumize!?`}}, + + {[]string{"abc", "abc", "

    abc

    "}, + []string{`abc`, + `

    abc

    `}}, + + {[]string{"

    def

    ", "def"}, + []string{`def`}}, + + {[]string{`Documize Logo:Documize`, + "Documize Logo:", `Documize`}, + []string{`Documize Logo:Documize`, + `Documize Logo:Documize`}}, + + {[]string{"
    • 1
    • 2
    • 3
    ", + "
    • one
    • two
    • three
    ", + "
    • 1
    • 2
    • 3
    • 4
    "}, + []string{`
    • 1one
    • 2two
    • 3three
    `, + `
    • 1
    • 2
    • 3
    • 4
    `}}, + + {[]string{doc1 + doc2 + doc3 + doc4, doc1 + doc2 + doc3 + doc4, doc1 + doc3 + doc4, doc1 + "" + doc2 + "" + doc3 + doc4, + doc1 + doc2 + "inserted" + doc3 + doc4, doc1 + doc2 + doc3 + "

    New Div

    " + doc4}, + []string{``, + `
  • Automated document formatting
  • `, + `Automated document formatting`, + `inserted`, + ``}}, + + {[]string{bbcNews1 + bbcNews2, bbcNews1 + "
    HTML-Diff-Inserted
    " + bbcNews2}, + []string{`
    HTML-Diff-Inserted
    `}}, + + {[]string{` + + + + + + + + + + +
    JackandJill
    DerbyandJoan
    `, + ` + + + + + + + + + + +
    JackandVera
    Derbylocomotiveworks
    `, + ` + + + + + + + + + + + + + + + +
    JackandJill
    SamsonandDelilah
    DerbyandJoan
    `, + ` + + + + + + + + + + + + + + + + + + + + +
    JackandJill
    SamsonandDelilah
    DerbyandJoan
    TweedledumandTweedledee
    `, `
    ...and now for something completely different.
    `}, + []string{` + + + + + + + + + + +
    JackandJillVera
    DerbyandlocomotiveJwoanrks
    `, + ` + + + + + + + + + + + + + + + +
    JackandJill
    DerbySamsonandJoDelilanh
    DerbyandJoan
    `, + ` + + + + + + + + + + + + + + + + + + + + +
    JackandJill
    DerbySamsonandJoDelilanh
    DerbyandJoan
    TweedledumandTweedledee
    `, + ` + + + + + + + + + + +
    JackandJill
    DerbyandJoan
    ...and now for something completely different.
    `}}, + + {[]string{"", `
    • A
    • B
    • C
    `}, + []string{`
    • A
    • B
    • C
    `}}, + + {[]string{`

    The following typographical conventions are used in this Standard:

    • The first occurrence of a new term is written in italics. [Example: … is considered normative. end example]
    • A term defined as a basic definition is written in bold. [Example: behavior — External … end example]
    • The name of an XML element is written using an Element style. [Example: The root element is document. end example]
    • The name of an XML element attribute is written using an Attribute style. [Example: … an id attribute. end example]
    • An XML element attribute value is written using a constant-width style. [Example: … value of CommentReference. end example]
    • An XML element type name is written using a Type style. [Example: … as values of the xsd:anyURI data type. end example]
    `, + `

    The following typographical conventions are used in this Standard:

    +
    • The first occurrence of a new term is written in italics. [Example: … is considered normative. end example]
    +
    • A term defined as a basic definition is written in bold. [Example: behaviorExternalend example]
    +
    • The name of an XML element attribute is written using an Attribute style. [Example: … an id attribute. end example]
    +
    • And here is another entry in the list!
    +
    • An XML element attribute value is written using a constant-width style. [Example: … value of CommentReference. end example]
    +
    • An XML element type name is written using a Type style. [Example: … as values of the xsd:anyURI data type. end example]
    +
     
    +
    elephant.
    `}, + []string{`

    The following typographical conventions are used in this Standard:

    +
    • The first occurrence of a new term is written in italics. [Example: … is considered normative. end example]
    +
    • A term defined as a basic definition is written in bold. [Example: behaviorExternalend example]
    +
    • The name of an XML element is written using an Element style. [Example: The ttroot element is document. end example]• The name of an XML element attribute is written using an Attribute style. [Example: … an id attribute. end example]
    +
    • And here is another entry in the list!
    +
    • An XML element attribute value is written using a constant-width style. [Example: … value of CommentReference. end example]
    +
    • An XML element type name is written using a Type style. [Example: … as values of the xsd:anyURI data type. end example]
    +
     
    +
    elephant.
    `}}, + + {[]string{` + +

    The Graph that Generates Stories

    + +

    StoryGraph is a graph designed to generate and narrate the causal interactions between things in a world. The graph can be populated with entities and expressive rules about the interactions between specific entities or different classes of entities. General rules can create new entities in the graph populated with the specific entities that triggered the rule and attributes defined by those entities. Entities have lifetimes and (coming soon) behaviors that trigger events over time.

    + +
    + +

    There is a more or less fleshed out example in ./example.js that produces sometimes surreal interactions in a snowy forest. To run that example, clone the repo and run the example directly with node.js:

    + +
    $ node example.js
    +
    + +

    You will see output something like this:

    + +
    The river joins with the shadow for a moment. The river does a whirling dance with the shadow. A bluejay discovers the river dancing with the shadow. A bluejay observes the patterns of the river dancing with the shadow. A bluejay dwells in the stillness of life. A duck approaches the whisper. A duck and the whisper pass eachother quietly.
    +
    + +

    This project is licensed under the terms of the MIT license.

    + +

    ##Types

    + +

    The first step is to define types. While it is possible to make rules that apply to specific things, you’ll probably want to make general rules that apply to classes of things. First the basics:

    + +`, `

    The Graph that Generates Stories

    +

    StoryGraph is a graph designed to generate and narrate the causal interactions between things in a world. The graph can be populated with entities and expressive rules about the interactions between specific entities or different classes of entities. General rules can create new entities in the graph populated with the specific entities that triggered the rule and attributes defined by those entities. Entities have lifetimes and (coming soon) behaviors that trigger events over time.

    +

    Story graph is inspired by progamming interactive worlds with linear logic by Chris Martens although it doesn’t realize any of the specific principles she develops in that thesis.

    +

    There is a more or less fleshed out example in ./example.js that produces sometimes surreal interactions in a snowy forest. To run that example, clone the repo and run the example directly with node.js:

    +
    $ node example.js
    +
    +

    Elliott has input another line.

    +

    You will see output something like this:

    +
    The river joins with the shadow for a moment. The river does a whirling dance with the shadow. A bluejay discovers the river dancing with the shadow. A bluejay observes the patterns of the river dancing with the shadow. A bluejay dwells in the stillness of life. A duck approaches the whisper. A duck and the whisper pass eachother quietly.
    +
    +

    This project is licensed under the terms of the MIT license.

    +

    ##Types

    +

    The first step is to define types. While it is possible to make rules that apply to specific things, you’ll probably want to make general rules that apply to classes of things. First the basics:

    `}, + []string{`

    The Graph that Generates Stories

    + +

    StoryGraph is a graph designed to generate and narrate the causal interactions between things in a world. The graph can be populated with entities and expressive rules about the interactions between specific entities or different classes of entities. General rules can create new entities in the graph populated with the specific entities that triggered the rule and attributes defined by those entities. Entities have lifetimes and (coming soon) behaviors that trigger events over time.

    + +

    Story graph is inspired by progamming interactive worlds with linear logic by Chris Martens although it doesn’t realize any of the specific principles she develops in that thesis.

    + +

    There is a more or less fleshed out example in ./example.js that produces sometimes surreal interactions in a snowy forest. To run that example, clone the repo and run the example directly with node.js:

    + +
    $ node example.js
    +
    +

    Elliott has input another line.

    +

    You will see output something like this:

    + +
    The river joins with the shadow for a moment. The river does a whirling dance with the shadow. A bluejay discovers the river dancing with the shadow. A bluejay observes the patterns of the river dancing with the shadow. A bluejay dwells in the stillness of life. A duck approaches the whisper. A duck and the whisper pass eachother quietly.
    +
    + +

    This project is licensed under the terms of the MIT license.

    + +

    ##Types

    + +

    The first step is to define types. While it is possible to make rules that apply to specific things, you’ll probably want to make general rules that apply to classes of things. First the basics:

    + +`}}, +} + +func TestSimple(t *testing.T) { + + for s, st := range simpleTests { + res, err := cfg.HTMLdiff(st.versions) + if err != nil { + t.Errorf("Simple test %d had error %v", s, err) + } + for d := range st.diffs { + if d < len(res) { + fn := fmt.Sprintf("testout/simple%d-%d.html", s, d) + err := ioutil.WriteFile(fn, []byte(res[d]), 0777) + if err != nil { + t.Error(err) + } + if !strings.Contains(res[d], st.diffs[d]) { + if len(res[d]) < 1024 { + t.Errorf("Simple test %d diff %d wanted: `%s` got: `%s`", s, d, st.diffs[d], res[d]) + } else { + t.Errorf("Simple test %d diff %d failed see file: `%s`", s, d, fn) + } + } + } + } + } + +} + +func TestTimeoutAndMemory(t *testing.T) { + dir := "." + string(os.PathSeparator) + "testin" + files, err := ioutil.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + testHTML := make([]string, 0, len(files)) + names := make([]string, 0, len(files)) + + for _, file := range files { + fn := file.Name() + if strings.HasSuffix(fn, ".html") { + ffn := dir + string(os.PathSeparator) + fn + dat, err := ioutil.ReadFile(ffn) + if err != nil { + t.Fatal(err) + } + testHTML = append(testHTML, string(dat)) + names = append(names, fn) + } + } + + fmt.Println("NOTE: this test may take a few minutes to run") + + var ms runtime.MemStats + var alloc1 uint64 + goroutineCount1 := 2 // the number of goroutines in a quiet state, more if test flags are used + for i := 0; i < 2; i++ { + testToMem(testHTML, names, t) + limit := 60 + var goroutineCount, secs int + for secs = 1; secs <= limit; secs++ { + time.Sleep(time.Second) // wait for the timeout goroutines to finish + goroutineCount, _ = runtime.GoroutineProfile(nil) + if goroutineCount == goroutineCount1 { + goto correctGoroutines + } + } + t.Error(fmt.Sprintln("after ", secs, "seconds, num goroutines", goroutineCount, "when should be", goroutineCount1)) + correctGoroutines: + runtime.GC() + runtime.ReadMemStats(&ms) + if alloc1 == 0 { + alloc1 = ms.Alloc // this is set here to allow for static data set-up by 1st pass through + fmt.Println("NOTE: base case established in", secs, "seconds. Memory used=", alloc1) + } else { + increase := (100.0 * float64(ms.Alloc) / float64(alloc1)) - 100.0 + if increase > 0.2 { // % + t.Error(fmt.Sprintln("run", i, "memory usage changed from", alloc1, "to", ms.Alloc, "increase:", ms.Alloc-alloc1, "which is", increase, "%")) + } + } + } +} + +func testToMem(testHTML, names []string, t *testing.T) { + for f := range testHTML { + args := []string{testHTML[f], strings.ToLower(testHTML[f])} + _, err := cfg.HTMLdiff(args) // don't care about the result as we are looking for crashes and time-outs + if err != nil { + if names[f] != "google.html" && names[f] != "bing.html" { // we expect errors on these two + t.Errorf("comparing %s with its lower-case self error: %s", names[f], err) + } + } + } +} diff --git a/vendor/github.com/documize/html-diff/nodes.go b/vendor/github.com/documize/html-diff/nodes.go new file mode 100644 index 00000000..40108ec6 --- /dev/null +++ b/vendor/github.com/documize/html-diff/nodes.go @@ -0,0 +1,68 @@ +package htmldiff + +import ( + "golang.org/x/net/html" + "golang.org/x/net/html/atom" +) + +func copyNode(to, from *html.Node) { + to.Attr = from.Attr + to.Data = from.Data + to.DataAtom = from.DataAtom + to.Namespace = from.Namespace + to.Type = from.Type +} + +func nodeEqual(base, comp *html.Node) bool { + return base.Data == comp.Data && nodeEqualExText(base, comp) +} + +// findBody finds the first body HTML node if it exists in the tree. Required to bypass the page title text. +func findBody(n *html.Node) *html.Node { + if n.Type == html.ElementNode && n.DataAtom == atom.Body { + return n + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + r := findBody(c) + if r != nil { + return r + } + } + return nil +} + +// find the first leaf in the tree that is a text node. +func firstLeaf(n *html.Node) (*html.Node, bool) { + if n != nil { + switch n.Type { + case html.TextNode: + return n, true + } + // no valid node found + for c := n.FirstChild; c != nil; c = c.NextSibling { + r, ok := firstLeaf(c) + if ok { + return r, ok + } + } + } + return nil, false +} + +// find if this or any parent is a container element where position is important like a list or table. +func inContainer(n *html.Node) bool { + if n == nil { + return false + } + if n.Type == html.ElementNode { + switch n.DataAtom { + case atom.Body: + return false + case atom.Td, atom.Th, atom.Tr, atom.Tbody, atom.Thead, atom.Tfoot, + atom.Table, atom.Caption, atom.Colgroup, atom.Col, // tables + atom.Li, atom.Ul, atom.Ol: // lists + return true + } + } + return inContainer(n.Parent) +} diff --git a/vendor/github.com/documize/html-diff/pos.go b/vendor/github.com/documize/html-diff/pos.go new file mode 100644 index 00000000..b6221898 --- /dev/null +++ b/vendor/github.com/documize/html-diff/pos.go @@ -0,0 +1,47 @@ +package htmldiff + +import "golang.org/x/net/html" + +// posTT gives the relative position within one level of a nested container. +type posTT struct { + nodesBefore int + node *html.Node +} + +// posT gives the relative position within a nested set of containers. +type posT []posTT + +// getPos returns the relative posion of this node within the enclosing containers, if there are any. +func getPos(n *html.Node) posT { + if n == nil { + return nil + } + depth := 0 + for root := n; inContainer(root); root = root.Parent { + depth++ + } + ret := make([]posTT, 0, depth) // for speed + for root := n; depth > 0; root = root.Parent { + var before int + for sib := root.Parent.FirstChild; sib != root; sib = sib.NextSibling { + if sib.Type == html.ElementNode { + before++ + } + } + ret = append(ret, posTT{before, root}) + depth-- + } + return ret +} + +func posEqual(a, b posT) bool { + if len(a) != len(b) { + return false + } + for i, aa := range a { + if aa.nodesBefore != b[i].nodesBefore { + return false + } + } + return true +} diff --git a/vendor/github.com/documize/html-diff/testin/bbc.html b/vendor/github.com/documize/html-diff/testin/bbc.html new file mode 100644 index 00000000..7656cdd7 --- /dev/null +++ b/vendor/github.com/documize/html-diff/testin/bbc.html @@ -0,0 +1,2589 @@ + + + + + + Home - BBC News + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    + + + + + + + +
    + + +
    +
    + +
    +
    +

    BBC News Home

    + + +
    + + +
    + +

    + + Top Stories +

    + + + +
    + + + +
    + +
    +
    + +
    +
    + +
    + + +
    + + +
    + + + + + + + + + + + + + +
    + +
    + + + + + + +
    + + +
    + + + +
    + +

    + + The Papers +

    + + + +
    + + + +
    + +

    + The Reporters + +

    +
    +
    + + + +
    +
    + + +
    + + + +
    + +

    + + Features +

    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    + + +
    + + + +
    + +

    + Explainers + +

    +
    +
    + + + +
    +
    + + +
    + + + +
    + +

    + Sport + +

    + +
    +
    + + + +
    +
    + + +
    + +
    +

    + + Weather +

    +
    +
    + + + +
    + +
    +
    +
    +
    + + + + + + + + +
    + +
    + + + + + + +
    + + +
    + + + + + +
    + +

    + + Follow Us +

    + + +
    + + + +
    + +

    + + Elsewhere on the BBC +

    +
    + + +
    + + +
    + + +
    +
    + +
    +
    + + + + +
    +
    +
    +
    + + + + + +
    + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/documize/html-diff/testin/bing.html b/vendor/github.com/documize/html-diff/testin/bing.html new file mode 100644 index 00000000..b967da45 --- /dev/null +++ b/vendor/github.com/documize/html-diff/testin/bing.html @@ -0,0 +1,57 @@ +Bing News

    Today's headlines

    EU referendum: Iain Duncan Smith claims Cameron's deal will do nothing to red…
    • Iain Duncan Smith says Cameron's EU deal will not curb immigration • Donald Tusk says deal is 'irreversible' • Cameron urged to sack Michael Gove over oppositio…Daily Telegraph
    Migrant crisis: EU meeting seeks to heal growing riftsMinisters from EU and Balkan nations are meeting in Brussels to try to heal divisions over a migrant crisis that could threaten the bloc's survival. Austria, Ser…BBC
    Jimmy Savile sex abuse report to be published - live• Tony Blackburn sacked by BBC ahead of sex abuse report • Stuart Hall blasts 'vindictive, malicious sex accusers' • BBC to pledge end to 'c…Daily Telegraph

    World

    Rubio pushed land deal as he backed law limiting criticsWASHINGTON (AP) — As a young state legislator, Marco Rubio pushed Miami-Dade County officials to allow a multimillion-dollar …
    Daily Mail
    Undercover with the Asian marriage investigatorsA growing number of British Asian families are hiring detectives to check on potential spouses. But does "honeytrapping" cross the …
    BBC
    'I love the poorly educated' Donald Trump WINS in Nevada in move …The outspoken billionaire crushed closest rivals Ted Cruz and Marco Rubio to secure his third successive victory. He picked up 45.9 …
    The Daily Express
    See all World news

    UK

    'Trendy' drama teacher who smeared Nutella over infatuated …A drama teacher who smeared Nutella over the naked body of an infatuated 14-year-old has been jailed for 20 months. Prosecutors …
    Daily Telegraph
    BBC SACKS Tony Blackburn ahead of damning report into Jimmy …The BBC has 'sacked' Radio 2 star Tony Blackburn after five decades on the air ahead of a damning report by Dame Janet Smith into …
    Daily Mail
    More than 2,000 drivers caught speeding at more than 100mph …Greater Manchester, Kent and Thames Valley police did not supply any information, while others submitted only some of the details.
    The Independent
    See all UK news

    Business

    Asian stocks tentative on anxiety over volatile oilMSCI's broadest index of Asia-Pacific shares outside Japan .MIAPJ0000PUS was down a touch, while Japan's Nikkei stock index …
    Reuters
    Lloyds profits fall on PPI claimsLloyds Banking Group has reported a 7% fall in annual pre-tax profits to £1.6bn compared with £1.8bn a year earlier. The bank …
    BBC
    Aston Martin's new DBX crossover will be built in Wales creating 1 …Aston Martin production will remain in the UK the carmaker announced on Wednesday, with the confirmation that it had chosen the St …
    Daily Mail
    See all Business news

    Politics

    Ted Cruz: 'Who knows what the heck Donald Trump would do as …Absent Trump still the focus at Fox News voter summit, as Republican rivals vie to cast themselves as best bet to beat the frontrunner …
    The Guardian
    Australia to boost defence spendingAustralia has announced a surge in defence spending, a move that reflects concern over military expansion in the region. Military …
    BBC
    Only one school has quit Safe Schools LGBTI program after parents' …Exclusive: Number undermines Eric Abetz’s claim that ‘mums and dads all around Australia’ do not want anti-bullying program in …
    The Guardian
    See all Politics news

    Entertainment

    Brits 2016: The real winners and losersAdele may have swept the board at the 2016 Brits, but there's always more to the show than the awards. On a night of joy and …
    BBC
    Stars get their BRITS out: Tearful Adele can barely contain herself (in …Last year's BRITs included the infamous Madonna cape tumble, but if the 2015 ceremony was about the spills, the 2016 BRIT Awards …
    Daily Mail
    Savile BBC abuse report to be published – live updatesWelcome to live coverage of the publication of Dame Janet Smith’s report into the BBC’s failure to prevent abuse by the TV star …
    The Guardian
    See all Entertainment news

    Sport

    Advantage Manchester City as Yaya Touré has last word against …Manchester City should be supremely confident of going beyond the Champions League last 16 at the third time of asking particularly if …
    The Guardian
    Rio Ferdinand jokes 'Fergie never wanted us horny like that' after …Manchester United manager Louis van Gaal bizarrely revealed on Wednesday that he has urged his players to be 'horny' for Europa …
    Daily Mail
    Atlético Madrid take a first-leg draw from 10-man PSV EindhovenPSV Eindhoven played for more than 20 minutes with 10 men but held on for a goalless draw at home against Atlético Madrid in the …
    The Guardian
    See all Sport news

    Sci/Tech

    Feds spank Asus with 20-year audit probe for router security blunderAsus has settled its case with the US Federal Trade Commission (FTC) after hackers pwned nearly 13,000 home routers via an …
    The Register
    Facebook set to be liked by more than half of BritonsMore than 33 million people in the UK are expected to log in regularly to the social network this year, with more than half of mobile …
    The Guardian
    MWC 2016: Pavel Durov backs Apple in not unlocking iPhonePavel Durov, the founder of the secure messaging app Telegram, says he backs Apple in resisting helping US authorities unlock an …
    BBC
    See all Sci/Tech news

    Health

    Avon and Wiltshire mental health trust told again to improveAn NHS trust providing adult mental health services must "significantly improve", inspectors have again warned. The Care Quality …
    BBC
    Pregnant women warned to cover themselves in repellent after ‘Zika …It's often cast away as being a health threat for people in a far away land - but now, the Zika virus is well and truly knocking on …
    Daily Mail
    Gluten-free products cost up to four times as much in supermarkets …Standard Tesco white or brown bread cost from 0.5 to 0.7 per 100g. Its gluten-free alternative costs more than four times the price at …
    The Independent
    See all Health news
    + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/documize/html-diff/testin/google.html b/vendor/github.com/documize/html-diff/testin/google.html new file mode 100644 index 00000000..49bf8494 --- /dev/null +++ b/vendor/github.com/documize/html-diff/testin/google.html @@ -0,0 +1,1261 @@ +Google News + +

    Top Stories

    See realtime coverage

    Jimmy Savile sex abuse report to be published - live

    Telegraph.co.uk - ‎1 hour ago‎
    ... • Tony Blackburn sacked by BBC ahead of sex abuse report • Stuart Hall blasts 'vindictive, malicious sex accusers' • BBC to pledge end to 'culture of deference' • Jimmy Savile's career at the BBC - in 60 seconds ...
    See realtime coverage

    Ofcom tells BT to open up cable network to rivals

    BBC News - ‎21 minutes ago‎
    Communications watchdog Ofcom has said BT must open up its cable network, allowing competition to improve UK internet connections.
    See realtime coverage

    Lloyds profits stung by £2.1bn PPI costs

    Telegraph.co.uk - ‎43 minutes ago‎
    Profits at Lloyds Banking Group fell 11pc in 2015 to £1.6bn as the lender continued to count the cost of the payment protection insurance mis-selling scandal.
    See realtime coverage

    Flying Scotsman on London King's Cross to York run

    BBC News - ‎1 hour ago‎
    One of the world's most famous locomotives has set off on its official return to the tracks. The Flying Scotsman is making the journey from London King's Cross to York, where it will go on display at the National Railway Museum (NRM).
    See realtime coverage

    Australia announces 'massive' increase in military spending

    The Hindu - ‎1 hour ago‎
    Australia on Thursday announced an ambitious plan to boost the country's defence capabilities by pledging to spend $ 139 billion over the next decade in what Prime Minister Malcolm Turnbull called “high stakes” and “momentous times” in Asia.
    See realtime coverage

    Indonesian police downplay Australia's travel warning

    SBS - ‎3 hours ago‎
    Indonesian police officers stand guard outside the house of a suspected militant following a raid in Malang, Indonesia, Saturday, Feb. 20, 2016.
    See realtime coverage

    Jeremy Corbyn to attend anti-nuclear weapons march

    The Guardian - ‎1 hour ago‎
    Corbyn's anti-nuclear stance puts him at odds with most of the parliamentary Labour party but not the grassroots membership. Photograph: Mark Kerrison/Demotix/Corbis.
    See realtime coverage

    Man detained after hostage situation at restaurant in central London

    Irish Independent - ‎1 hour ago‎
    A man has been detained by police following a hostage situation at a Bella Italia restaurant in Leicester Square. Share. Facebook · Twitter · Google · Email.
    See realtime coverage

    Tom Watson vows to defy Jeremy Corbyn and vote in favour of Trident

    Mirror.co.uk - ‎13 hours ago‎
    Labour big beast Tom Watson vowed tonight to defy Jeremy Corbyn and vote in favour of Trident. The Deputy Leader said it is vital to give “certainty” to manufacturers and the rest of the world that Britain will keep its nuclear deterrent despite Mr ...
    See realtime coverage

    Thousands of racing greyhounds 'may be killed' after retiring every year

    Evening Standard - ‎1 hour ago‎
    Thousands of retired racing greyhounds are potentially being culled every year, according to a parliamentary report. The Environment, Food and Rural Affairs Committee warns that between 1,000 and 3,700 dogs are unaccounted for each year.
    See realtime coverage

    Japan's Sharp Accepts Takeover by Taiwan's Hon Hai

    New York Times - ‎18 minutes ago‎
    TOKYO - Sharp Corp. agreed Thursday to a 489 billion yen ($4.4 billion) takeover by Taiwan's Hon Hai Precision Industry Co., also known as Foxconn, becoming the first major Japanese electronics maker to be acquired by a foreign company.
    See realtime coverage

    AB InBev warns of slowing emerging markets as results miss target

    Financial Times - ‎28 minutes ago‎
    AB InBev has warned that a slowdown in markets such as Brazil and China will weigh on the group during 2016 after the brewer behind Stella Artois reported full-year results that missed analyst expectations.
    See realtime coverage

    Spirent sees wireless testing division facing headwinds in 2016

    Reuters UK - ‎1 hour ago‎
    Spirent Communications Plc (SPT.L), a British telecoms testing provider, said it expects revenue from the wireless device testing segment to fall by 14 million pounds in 2016.
    See realtime coverage

    Facebook has missed a trick or two with its limited Reactions

    BetaNews - ‎21 minutes ago‎
    After years of pestering, yesterday Facebook finally supplemented the famous Like button with five additional Reactions. To the disappointment of many, the much-requested Dislike button is yet to make an appearance, but this is not the only way in ...
    See realtime coverage

    Verizon supports 'strong encryption with no backdoors': CEO

    The Star Online - ‎2 hours ago‎
    Weighing in: Verizon Communications Inc supports 'the availability of strong encryption with no backdoors,' Chief Executive Lowell McAdam said on Feb 24.
    See realtime coverage

    Nigeria: Blackberry Launches Professional Security Services

    AllAfrica.com - ‎1 hour ago‎
    Canadian phone maker, BlackBerry Limited Wednesday announced the launch of its new Professional Cybersecurity Services practice that will further expand BlackBerry's security portfolio by offering organizations new consulting services, tools and best ...
    See realtime coverage

    The Brit Awards: If pop has a future, it's not going to be British

    Telegraph.co.uk - ‎57 minutes ago‎
    Adele crashed down on the 2016 awards like a singing tsunami, wiping away all opposition. She won almost everything she was nominated for, and you can only suppose that Coldplay and James Bay could count themselves lucky she wasn't eligible in the ...
    See realtime coverage

    Audience walkouts as Sarah Kane play, Cleansed, is revived

    Waikato Times - ‎27 minutes ago‎
    A revival of a brutal play in London showing rape, torture, incest, electrocution, sex assignment surgery and a man having his tongue ripped out has caused audience members to faint and walk out.
    See realtime coverage

    Merlin see profits rise despite Alton Towers accident

    BBC News - ‎38 minutes ago‎
    Profits at theme parks operator Merlin Entertainments have edged up despite last summer's Alton Towers accident which left five people injured.
    See realtime coverage

    Andy King: Leicester City 'under no pressure'

    BBC News - ‎1 hour ago‎
    Leicester City midfielder Andy King says there is absolutely no pressure on the Premier League leaders. The Foxes are currently two points clear at the top with 12 games remaining despite being bottom of the table at the same stage last season.
    See realtime coverage

    Dynamo Kyiv vs. Manchester City – (Watch Live Stream NOW!)

    Nilsen Report - ‎Feb 23, 2016‎
    City have scored more than any other team in the Premier League [alongside Leicester] and their recent defeats mean nothing. Their squad, even without all the injury absentees, includes many top players.
    See realtime coverage

    Lewis Hamilton: FI changes won't have much effect

    RTE.ie - ‎30 minutes ago‎
    Lewis Hamilton has taken aim at Formula One's power brokers in the wake of proposed changes designed to usher in a new era for the sport.
    See realtime coverage

    SpaceX awarded NASA contract for 5 International Space Station cargo missions worth ~$700mn

    RT - ‎3 hours ago‎
    A semi-secret deal between NASA and SpaceX, signed around Christmas but only coming to light now, covers five new re-supply launches to the International Space Station (ISS) and is allegedly worth $700 million.
    See realtime coverage

    Scientists trace mystery 'alien signals' to distant galaxy

    The Nation - ‎2 hours ago‎
    For the first time, scientists have successfully traced mysterious “fast radio bursts” (FRBs), which have been speculated to be signs of extraterrestrial intelligence, to a galaxy six billion light years away.

    Next-Gen Robot Walks Like a Man, Stands Up to Being Pushed

    Tolerance.ca - ‎8 hours ago‎
    If you're not completely heartless, it can be difficult to watch the newest version of the Atlas robot get bullied, teased and pushed around without feeling a twinge of discomfort.
    See realtime coverage

    Mystery of plane spotted at bottom of Minneapolis lake solved

    The Independent - ‎10 hours ago‎
    The mystery behind a ghostly image, seemingly showing a passenger plane “submerged” in a US lake on Google Maps, has been solved.
    See realtime coverage

    Teenagers who stay at school until 18 are more likely to stave off dementia

    Daily Mail - ‎4 hours ago‎
    Teenagers who stay at school until at least the age of 18 are more likely to stave off the effects of dementia in later life, research suggests.
    See realtime coverage

    Learning to live with cancer is more effective than killing it, say scientists

    Irish Independent - ‎2 hours ago‎
    Managing cancer with low doses of chemotherapy could be more effective than attempting to kill the disease, scientists believe. Share.
    See realtime coverage

    Pancreatic cancer identified as 4 different diseases

    Times of India - ‎24 minutes ago‎
    WASHINGTON DC: A recent research has identified that pancreatic cancer is not one, but four diseases, each with different genetic triggers and survival rates, paving the way for more accurate diagnoses and treatments.
    See realtime coverage

    Hepatitis C warning for more than 8000 patients after NHS worker tests positive

    Telegraph.co.uk - ‎Feb 23, 2016‎
    More than 8,000 patients who may have been treated by a former NHS healthcare worker who tested positive for hepatitis C have been recalled for blood tests.
    Weather for Edinburgh, Scotland
    Today
    MOSTLY_SUNNY
     -2°
    Fri
    MOSTLY_CLOUDY
     -1°
    Sat
    PARTLY_CLOUDY
     -1°
    Sun
    MOSTLY_SUNNY
     
     - 
     

    + + + + \ No newline at end of file diff --git a/vendor/github.com/documize/html-diff/testin/reuters.html b/vendor/github.com/documize/html-diff/testin/reuters.html new file mode 100644 index 00000000..0dc1505c --- /dev/null +++ b/vendor/github.com/documize/html-diff/testin/reuters.html @@ -0,0 +1,1749 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Breaking News, Top News & Latest News Headlines | Reuters.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    +
    + +
    +
    + + +
    + +
    + +
    +
    +
    +
    +
    + +
    + + +
    + + + +
    + +
    + + + +
    + +
    + +
    +
    +
    +
    + + + + + + + +
    +
    + +
    +
    + +
    + +
    +
    +
    +
    +

    News

    +
    + +
    + +
    + +
    +
    + + +
    + +
    +
    +

    Topics also related to Top News:

    + +
    +
    +
    +
    + +
    +
    + +
    +
    + Photo +

    Obama weighs Republican for Supreme Court +

    WASHINGTON President Barack Obama is considering appointing a moderate Republican to the Supreme Court, a source close to the process said on Wednesday, but leaders in the Republican-led Senate held firm to their threat to block anyone he nominates. | Video +

    +
    +
    +
    + + +
    + + + +
    + +
    +
    +
    + + + +
    + +
    +
    + + + + +
    +
    + +
    +

    + Recent Top News

    +
    +
    +

    Asian stocks slip as China markets slide, oil prices dip +

    TOKYO Asian shares slipped on Thursday as crude oil prices seesawed and Chinese shares dived, rekindling anxiety about the impact of high market volatility on the global economy on the eve of a G20 meeting in Shanghai.

    +
    + 1:52am EST
    +

    Eritrea won't shorten national service despite migration fears +

    ASMARA Eritrea is not prepared to stop forcing its youth into lengthy stretches of work as soldiers and civil servants, a conscription policy that is driving waves of refugees to make the perilous trip across the Sahara desert and Mediterranean Sea to Europe.

    +
    + 2:10am EST
    +

    The Washington insiders who work to get Chinese deals approved +

    WASHINGTON/NEW YORK A spate of proposed Chinese takeovers of U.S. companies, from the Chicago Stock Exchange to makers of high-end semiconductors, has created a vibrant business for a small circuit of Washington insiders who advise on how to get cross-border deals approved by the U.S. government.

    +
    + 24 Feb 2016
    +

    U.S. to boost South China Sea freedom of navigation moves, admiral says +

    WASHINGTON The United States, which is worried by China's military buildup to assert dominance in the South China Sea, will increase freedom-of-navigation operations there, a senior Pentagon official said on Wednesday.

    +
    + + + World, + China, + South China Sea + 12:29am EST
    +

    Connecticut prosecutors ask court to order Kennedy kin back to jail +

    Connecticut prosecutors asked the state's top court on Wednesday to return Kennedy family member Michael Skakel to prison to serve the last nine years of a sentence imposed after he was convicted of murdering a friend four decades ago. | Video +

    +
    + 24 Feb 2016
    +
    +
    +
    + + + + + +
    + + + +
    + +
    + + + + + + +
    + +
    + +
    +
    + +
    +
    + + + +
    + +
    + + +
    + +
    +

    + + U.S. News +

    +
    +
    +
    + Photo +

    U.S. court allows Louisiana abortion restrictions to go into effect +

    A U.S. appeals court on Wednesday allowed Louisiana to enforce a restrictive 2014 abortion law critics say is aimed at shutting clinics, ending a halt to the measure handed out by a lower court judge earlier this year.

    +
    +
    +
    +
    + + + +
    + +
    +

    + + World News +

    +
    +
    +
    + Photo +

    Syrian opposition supports idea of two-week ceasefire +

    BEIRUT/WASHINGTON Syria's opposition indicated on Wednesday it was ready for a two-week truce in Syria, saying it was a chance to test the seriousness of the other side's commitment to a U.S.-Russian plan for a cessation of hostilities. | Video +

    +
    +
    +
    +
    + + + + +
    +
    + +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    +
    + + +
    + +
    +
    +

    Topics also related to Top News:

    + +
    +
    +
    +
    +
    + +
    +
    +
    + + +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/vendor/github.com/documize/html-diff/treerunes.go b/vendor/github.com/documize/html-diff/treerunes.go new file mode 100644 index 00000000..c91cc057 --- /dev/null +++ b/vendor/github.com/documize/html-diff/treerunes.go @@ -0,0 +1,124 @@ +package htmldiff + +import ( + "github.com/mb0/diff" + + "golang.org/x/net/html" +) + +// treeRune holds an individual rune in the HTML along with the node it is in and, for convienience, its position (if in a container). +type treeRune struct { + leaf *html.Node + letter rune + pos posT +} + +// diffData is a type that exists in order to provide a diff.Data interface. It holds the two sets of treeRunes to difference. +type diffData struct { + a, b *[]treeRune +} + +// Equal exists to fulfill the diff.Data interface. +// NOTE: this is usually the most called function in the package! +func (dd diffData) Equal(i, j int) bool { + if (*dd.a)[i].letter != (*dd.b)[j].letter { + return false + } + if !posEqual((*dd.a)[i].pos, (*dd.b)[j].pos) { + return false + } + return nodeBranchesEqual((*dd.a)[i].leaf, (*dd.b)[j].leaf) +} + +// nodeBranchesEqual checks that two leaves come from branches that can be compared. +func nodeBranchesEqual(leafA, leafB *html.Node) bool { + if !nodeEqualExText(leafA, leafB) { + return false + } + if leafA.Parent == nil && leafB.Parent == nil { + return true // at the top of the tree + } + if leafA.Parent != nil && leafB.Parent != nil { + return nodeEqualExText(leafA.Parent, leafB.Parent) // go up to the next level + } + return false // one of the leaves has a parent, the other does not +} + +// attrEqual checks that the attributes of two nodes are the same. +func attrEqual(base, comp *html.Node) bool { + if len(comp.Attr) != len(base.Attr) { + return false + } + for a := range comp.Attr { + if comp.Attr[a].Key != base.Attr[a].Key || + comp.Attr[a].Namespace != base.Attr[a].Namespace || + comp.Attr[a].Val != base.Attr[a].Val { + return false + } + } + return true +} + +// compares nodes excluding their text +func nodeEqualExText(base, comp *html.Node) bool { + if comp.DataAtom != base.DataAtom || + comp.Namespace != base.Namespace || + comp.Type != base.Type { + return false + } + return attrEqual(base, comp) +} + +// renders a tree of nodes into a slice of treeRunes. +func renderTreeRunes(n *html.Node, tr *[]treeRune) { + p := getPos(n) + if n.FirstChild == nil { // it is a leaf node + switch n.Type { + case html.TextNode: + if len(n.Data) == 0 { + *tr = append(*tr, treeRune{leaf: n, letter: '\u200b' /* zero-width space */, pos: p}) // make sure we catch the node, even if no data + } else { + for _, r := range []rune(n.Data) { + *tr = append(*tr, treeRune{leaf: n, letter: r, pos: p}) + } + } + default: + *tr = append(*tr, treeRune{leaf: n, letter: 0, pos: p}) + } + } else { + for c := n.FirstChild; c != nil; c = c.NextSibling { + renderTreeRunes(c, tr) + } + } +} + +// wrapper for diff.Granular() -- should only concatanate changes for similar text nodes +func granular(gran int, dd diffData, changes []diff.Change) []diff.Change { + ret := make([]diff.Change, 0, len(changes)) + startSame := 0 + changeCount := 0 + lastAleaf, lastBleaf := (*dd.a)[0].leaf, (*dd.b)[0].leaf + for c, cc := range changes { + if cc.A < len(*dd.a) && cc.B < len(*dd.b) && + lastAleaf.Type == html.TextNode && lastBleaf.Type == html.TextNode && + (*dd.a)[cc.A].leaf == lastAleaf && (*dd.b)[cc.B].leaf == lastBleaf && + nodeEqualExText(lastAleaf, lastBleaf) { // TODO is this last constraint required? + // do nothing yet, queue it up until there is a difference + changeCount++ + } else { // no match + if changeCount > 0 { // flush + ret = append(ret, diff.Granular(gran, changes[startSame:startSame+changeCount])...) + } + ret = append(ret, cc) + startSame = c + 1 // the one after this + changeCount = 0 + if cc.A < len(*dd.a) && cc.B < len(*dd.b) { + lastAleaf, lastBleaf = (*dd.a)[cc.A].leaf, (*dd.b)[cc.B].leaf + } + } + } + if changeCount > 0 { // flush + ret = append(ret, diff.Granular(gran, changes[startSame:])...) + } + return ret +} diff --git a/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/LICENSE b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/LICENSE new file mode 100644 index 00000000..fe5a16b2 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012 Martin Schnabel. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/README.md b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/README.md new file mode 100644 index 00000000..ce824303 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/README.md @@ -0,0 +1,34 @@ +diff +==== + +A difference algorithm package for go. + +The algorithm is described by Eugene Myers in +["An O(ND) Difference Algorithm and its Variations"](http://www.xmailserver.org/diff2.pdf). + +Example +------- +You can use diff.Ints, diff.Runes, diff.ByteStrings, and diff.Bytes + + diff.Runes([]rune("sögen"), []rune("mögen")) // returns []Changes{{0,0,1,1}} + +or you can implement diff.Data + + type MixedInput struct { + A []int + B []string + } + func (m *MixedInput) Equal(i, j int) bool { + return m.A[i] == len(m.B[j]) + } + +and call + + m := &MixedInput{..} + diff.Diff(len(m.A), len(m.B), m) + +Also has granularity functions to merge changes that are close by. + + diff.Granular(1, diff.ByteStrings("emtire", "umpire")) // returns []Changes{{0,0,3,3}} + +Documentation at http://godoc.org/github.com/mb0/diff diff --git a/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff.go b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff.go new file mode 100644 index 00000000..1047abc7 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff.go @@ -0,0 +1,222 @@ +// Copyright 2012 Martin Schnabel. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package diff implements a difference algorithm. +// The algorithm is described in "An O(ND) Difference Algorithm and its Variations", Eugene Myers, Algorithmica Vol. 1 No. 2, 1986, pp. 251-266. +package diff + +// A type that satisfies diff.Data can be diffed by this package. +// It typically has two sequences A and B of comparable elements. +type Data interface { + // Equal returns whether the elements at i and j are considered equal. + Equal(i, j int) bool +} + +// ByteStrings returns the differences of two strings in bytes. +func ByteStrings(a, b string) []Change { + return Diff(len(a), len(b), &strings{a, b}) +} + +type strings struct{ a, b string } + +func (d *strings) Equal(i, j int) bool { return d.a[i] == d.b[j] } + +// Bytes returns the difference of two byte slices +func Bytes(a, b []byte) []Change { + return Diff(len(a), len(b), &bytes{a, b}) +} + +type bytes struct{ a, b []byte } + +func (d *bytes) Equal(i, j int) bool { return d.a[i] == d.b[j] } + +// Ints returns the difference of two int slices +func Ints(a, b []int) []Change { + return Diff(len(a), len(b), &ints{a, b}) +} + +type ints struct{ a, b []int } + +func (d *ints) Equal(i, j int) bool { return d.a[i] == d.b[j] } + +// Runes returns the difference of two rune slices +func Runes(a, b []rune) []Change { + return Diff(len(a), len(b), &runes{a, b}) +} + +type runes struct{ a, b []rune } + +func (d *runes) Equal(i, j int) bool { return d.a[i] == d.b[j] } + +// Granular merges neighboring changes smaller than the specified granularity. +// The changes must be ordered by ascending positions as returned by this package. +func Granular(granularity int, changes []Change) []Change { + if len(changes) == 0 { + return changes + } + gap := 0 + for i := 1; i < len(changes); i++ { + curr := changes[i] + prev := changes[i-gap-1] + // same as curr.B-(prev.B+prev.Ins); consistency is key + if curr.A-(prev.A+prev.Del) <= granularity { + // merge changes: + curr = Change{ + A: prev.A, B: prev.B, // start at same spot + Del: curr.A - prev.A + curr.Del, // from first to end of second + Ins: curr.B - prev.B + curr.Ins, // from first to end of second + } + gap++ + } + changes[i-gap] = curr + } + return changes[:len(changes)-gap] +} + +// Diff returns the differences of data. +// data.Equal is called repeatedly with 0<=i m { + c.flags = make([]byte, n) + } else { + c.flags = make([]byte, m) + } + c.max = n + m + 1 + c.compare(0, 0, n, m) + return c.result(n, m) +} + +// A Change contains one or more deletions or inserts +// at one position in two sequences. +type Change struct { + A, B int // position in input a and b + Del int // delete Del elements from input a + Ins int // insert Ins elements from input b +} + +type context struct { + data Data + flags []byte // element bits 1 delete, 2 insert + max int + // forward and reverse d-path endpoint x components + forward, reverse []int +} + +func (c *context) compare(aoffset, boffset, alimit, blimit int) { + // eat common prefix + for aoffset < alimit && boffset < blimit && c.data.Equal(aoffset, boffset) { + aoffset++ + boffset++ + } + // eat common suffix + for alimit > aoffset && blimit > boffset && c.data.Equal(alimit-1, blimit-1) { + alimit-- + blimit-- + } + // both equal or b inserts + if aoffset == alimit { + for boffset < blimit { + c.flags[boffset] |= 2 + boffset++ + } + return + } + // a deletes + if boffset == blimit { + for aoffset < alimit { + c.flags[aoffset] |= 1 + aoffset++ + } + return + } + x, y := c.findMiddleSnake(aoffset, boffset, alimit, blimit) + c.compare(aoffset, boffset, x, y) + c.compare(x, y, alimit, blimit) +} + +func (c *context) findMiddleSnake(aoffset, boffset, alimit, blimit int) (int, int) { + // midpoints + fmid := aoffset - boffset + rmid := alimit - blimit + // correct offset in d-path slices + foff := c.max - fmid + roff := c.max - rmid + isodd := (rmid-fmid)&1 != 0 + maxd := (alimit - aoffset + blimit - boffset + 2) / 2 + // allocate when first used + if c.forward == nil { + c.forward = make([]int, 2*c.max) + c.reverse = make([]int, 2*c.max) + } + c.forward[c.max+1] = aoffset + c.reverse[c.max-1] = alimit + var x, y int + for d := 0; d <= maxd; d++ { + // forward search + for k := fmid - d; k <= fmid+d; k += 2 { + if k == fmid-d || k != fmid+d && c.forward[foff+k+1] > c.forward[foff+k-1] { + x = c.forward[foff+k+1] // down + } else { + x = c.forward[foff+k-1] + 1 // right + } + y = x - k + for x < alimit && y < blimit && c.data.Equal(x, y) { + x++ + y++ + } + c.forward[foff+k] = x + if isodd && k > rmid-d && k < rmid+d { + if c.reverse[roff+k] <= c.forward[foff+k] { + return x, x - k + } + } + } + // reverse search x,y correspond to u,v + for k := rmid - d; k <= rmid+d; k += 2 { + if k == rmid+d || k != rmid-d && c.reverse[roff+k-1] < c.reverse[roff+k+1] { + x = c.reverse[roff+k-1] // up + } else { + x = c.reverse[roff+k+1] - 1 // left + } + y = x - k + for x > aoffset && y > boffset && c.data.Equal(x-1, y-1) { + x-- + y-- + } + c.reverse[roff+k] = x + if !isodd && k >= fmid-d && k <= fmid+d { + if c.reverse[roff+k] <= c.forward[foff+k] { + // lookup opposite end + x = c.forward[foff+k] + return x, x - k + } + } + } + } + panic("should never be reached") +} + +func (c *context) result(n, m int) (res []Change) { + var x, y int + for x < n || y < m { + if x < n && y < m && c.flags[x]&1 == 0 && c.flags[y]&2 == 0 { + x++ + y++ + } else { + a := x + b := y + for x < n && (y >= m || c.flags[x]&1 != 0) { + x++ + } + for y < m && (x >= n || c.flags[y]&2 != 0) { + y++ + } + if a < x || b < y { + res = append(res, Change{a, b, x - a, y - b}) + } + } + } + return +} diff --git a/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff_test.go b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff_test.go new file mode 100644 index 00000000..530d5fde --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/diff_test.go @@ -0,0 +1,239 @@ +// Copyright 2012 Martin Schnabel. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package diff_test + +import ( + "github.com/mb0/diff" + "testing" +) + +type testcase struct { + name string + a, b []int + res []diff.Change +} + +var tests = []testcase{ + {"shift", + []int{1, 2, 3}, + []int{0, 1, 2, 3}, + []diff.Change{{0, 0, 0, 1}}, + }, + {"push", + []int{1, 2, 3}, + []int{1, 2, 3, 4}, + []diff.Change{{3, 3, 0, 1}}, + }, + {"unshift", + []int{0, 1, 2, 3}, + []int{1, 2, 3}, + []diff.Change{{0, 0, 1, 0}}, + }, + {"pop", + []int{1, 2, 3, 4}, + []int{1, 2, 3}, + []diff.Change{{3, 3, 1, 0}}, + }, + {"all changed", + []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + []int{10, 11, 12, 13, 14}, + []diff.Change{ + {0, 0, 10, 5}, + }, + }, + {"all same", + []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + []diff.Change{}, + }, + {"wrap", + []int{1}, + []int{0, 1, 2, 3}, + []diff.Change{ + {0, 0, 0, 1}, + {1, 2, 0, 2}, + }, + }, + {"snake", + []int{0, 1, 2, 3, 4, 5}, + []int{1, 2, 3, 4, 5, 6}, + []diff.Change{ + {0, 0, 1, 0}, + {6, 5, 0, 1}, + }, + }, + // note: input is ambiguous + // first two traces differ from fig.1 + // it still is a lcs and ses path + {"paper fig. 1", + []int{1, 2, 3, 1, 2, 2, 1}, + []int{3, 2, 1, 2, 1, 3}, + []diff.Change{ + {0, 0, 1, 1}, + {2, 2, 1, 0}, + {5, 4, 1, 0}, + {7, 5, 0, 1}, + }, + }, +} + +func TestDiffAB(t *testing.T) { + for _, test := range tests { + res := diff.Ints(test.a, test.b) + if len(res) != len(test.res) { + t.Error(test.name, "expected length", len(test.res), "for", res) + continue + } + for i, c := range test.res { + if c != res[i] { + t.Error(test.name, "expected ", c, "got", res[i]) + } + } + } +} + +func TestDiffBA(t *testing.T) { + // interesting: fig.1 Diff(b, a) results in the same path as `diff -d a b` + tests[len(tests)-1].res = []diff.Change{ + {0, 0, 2, 0}, + {3, 1, 1, 0}, + {5, 2, 0, 1}, + {7, 5, 0, 1}, + } + for _, test := range tests { + res := diff.Ints(test.b, test.a) + if len(res) != len(test.res) { + t.Error(test.name, "expected length", len(test.res), "for", res) + continue + } + for i, c := range test.res { + // flip change data also + rc := diff.Change{c.B, c.A, c.Ins, c.Del} + if rc != res[i] { + t.Error(test.name, "expected ", rc, "got", res[i]) + } + } + } +} + +func diffsEqual(a, b []diff.Change) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +func TestGranularStrings(t *testing.T) { + a := "abcdefghijklmnopqrstuvwxyza" + b := "AbCdeFghiJklmnOpqrstUvwxyzab" + // each iteration of i increases granularity and will absorb one more lower-letter-followed-by-upper-letters sequence + changesI := [][]diff.Change{ + {{0, 0, 1, 1}, {2, 2, 1, 1}, {5, 5, 1, 1}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}}, + {{0, 0, 3, 3}, {5, 5, 1, 1}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}}, + {{0, 0, 6, 6}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}}, + {{0, 0, 10, 10}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}}, + {{0, 0, 15, 15}, {20, 20, 1, 1}, {27, 27, 0, 1}}, + {{0, 0, 21, 21}, {27, 27, 0, 1}}, + {{0, 0, 27, 28}}, + } + for i := 0; i < len(changesI); i++ { + diffs := diff.Granular(i, diff.ByteStrings(a, b)) + if !diffsEqual(diffs, changesI[i]) { + t.Errorf("expected %v, got %v", diffs, changesI[i]) + } + } +} + +func TestDiffRunes(t *testing.T) { + a := []rune("brown fox jumps over the lazy dog") + b := []rune("brwn faax junps ovver the lay dago") + res := diff.Runes(a, b) + echange := []diff.Change{ + {2, 2, 1, 0}, + {7, 6, 1, 2}, + {12, 12, 1, 1}, + {18, 18, 0, 1}, + {27, 28, 1, 0}, + {31, 31, 0, 2}, + {32, 34, 1, 0}, + } + for i, c := range res { + t.Log(c) + if c != echange[i] { + t.Error("expected", echange[i], "got", c) + } + } +} + +func TestDiffByteStrings(t *testing.T) { + a := "brown fox jumps over the lazy dog" + b := "brwn faax junps ovver the lay dago" + res := diff.ByteStrings(a, b) + echange := []diff.Change{ + {2, 2, 1, 0}, + {7, 6, 1, 2}, + {12, 12, 1, 1}, + {18, 18, 0, 1}, + {27, 28, 1, 0}, + {31, 31, 0, 2}, + {32, 34, 1, 0}, + } + for i, c := range res { + t.Log(c) + if c != echange[i] { + t.Error("expected", echange[i], "got", c) + } + } +} + +type ints struct{ a, b []int } + +func (d *ints) Equal(i, j int) bool { return d.a[i] == d.b[j] } +func BenchmarkDiff(b *testing.B) { + t := tests[len(tests)-1] + d := &ints{t.a, t.b} + n, m := len(d.a), len(d.b) + for i := 0; i < b.N; i++ { + diff.Diff(n, m, d) + } +} + +func BenchmarkInts(b *testing.B) { + t := tests[len(tests)-1] + d1 := t.a + d2 := t.b + for i := 0; i < b.N; i++ { + diff.Ints(d1, d2) + } +} + +func BenchmarkDiffRunes(b *testing.B) { + d1 := []rune("1231221") + d2 := []rune("321213") + for i := 0; i < b.N; i++ { + diff.Runes(d1, d2) + } +} + +func BenchmarkDiffBytes(b *testing.B) { + d1 := []byte("lorem ipsum dolor sit amet consectetur") + d2 := []byte("lorem lovesum daenerys targaryen ami consecteture") + for i := 0; i < b.N; i++ { + diff.Bytes(d1, d2) + } +} + +func BenchmarkDiffByteStrings(b *testing.B) { + d1 := "lorem ipsum dolor sit amet consectetur" + d2 := "lorem lovesum daenerys targaryen ami consecteture" + for i := 0; i < b.N; i++ { + diff.ByteStrings(d1, d2) + } +} diff --git a/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/example_test.go b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/example_test.go new file mode 100644 index 00000000..fd7a2d3c --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/github.com/mb0/diff/example_test.go @@ -0,0 +1,57 @@ +// Copyright 2012 Martin Schnabel. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package diff_test + +import ( + "fmt" + "github.com/mb0/diff" +) + +// Diff on inputs with different representations +type MixedInput struct { + A []int + B []string +} + +var names map[string]int + +func (m *MixedInput) Equal(a, b int) bool { + return m.A[a] == names[m.B[b]] +} + +func ExampleDiff() { + names = map[string]int{ + "one": 1, + "two": 2, + "three": 3, + } + + m := &MixedInput{ + []int{1, 2, 3, 1, 2, 2, 1}, + []string{"three", "two", "one", "two", "one", "three"}, + } + changes := diff.Diff(len(m.A), len(m.B), m) + for _, c := range changes { + fmt.Println("change at", c.A, c.B) + } + // Output: + // change at 0 0 + // change at 2 2 + // change at 5 4 + // change at 7 5 +} + +func ExampleGranular() { + a := "hElLo!" + b := "hello!" + changes := diff.Granular(5, diff.ByteStrings(a, b)) // ignore small gaps in differences + for l := len(changes) - 1; l >= 0; l-- { + change := changes[l] + b = b[:change.B] + "|" + b[change.B:change.B+change.Ins] + "|" + b[change.B+change.Ins:] + } + fmt.Println(b) + // Output: + // h|ell|o! +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom.go new file mode 100644 index 00000000..cd0a8ac1 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom.go @@ -0,0 +1,78 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package atom provides integer codes (also known as atoms) for a fixed set of +// frequently occurring HTML strings: tag names and attribute keys such as "p" +// and "id". +// +// Sharing an atom's name between all elements with the same tag can result in +// fewer string allocations when tokenizing and parsing HTML. Integer +// comparisons are also generally faster than string comparisons. +// +// The value of an atom's particular code is not guaranteed to stay the same +// between versions of this package. Neither is any ordering guaranteed: +// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to +// be dense. The only guarantees are that e.g. looking up "div" will yield +// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. +package atom // import "golang.org/x/net/html/atom" + +// Atom is an integer code for a string. The zero value maps to "". +type Atom uint32 + +// String returns the atom's name. +func (a Atom) String() string { + start := uint32(a >> 8) + n := uint32(a & 0xff) + if start+n > uint32(len(atomText)) { + return "" + } + return atomText[start : start+n] +} + +func (a Atom) string() string { + return atomText[a>>8 : a>>8+a&0xff] +} + +// fnv computes the FNV hash with an arbitrary starting value h. +func fnv(h uint32, s []byte) uint32 { + for i := range s { + h ^= uint32(s[i]) + h *= 16777619 + } + return h +} + +func match(s string, t []byte) bool { + for i, c := range t { + if s[i] != c { + return false + } + } + return true +} + +// Lookup returns the atom whose name is s. It returns zero if there is no +// such atom. The lookup is case sensitive. +func Lookup(s []byte) Atom { + if len(s) == 0 || len(s) > maxAtomLen { + return 0 + } + h := fnv(hash0, s) + if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { + return a + } + if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { + return a + } + return 0 +} + +// String returns a string whose contents are equal to s. In that sense, it is +// equivalent to string(s) but may be more efficient. +func String(s []byte) string { + if a := Lookup(s); a != 0 { + return a.String() + } + return string(s) +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom_test.go new file mode 100644 index 00000000..6e33704d --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/atom_test.go @@ -0,0 +1,109 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package atom + +import ( + "sort" + "testing" +) + +func TestKnown(t *testing.T) { + for _, s := range testAtomList { + if atom := Lookup([]byte(s)); atom.String() != s { + t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String()) + } + } +} + +func TestHits(t *testing.T) { + for _, a := range table { + if a == 0 { + continue + } + got := Lookup([]byte(a.String())) + if got != a { + t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a)) + } + } +} + +func TestMisses(t *testing.T) { + testCases := []string{ + "", + "\x00", + "\xff", + "A", + "DIV", + "Div", + "dIV", + "aa", + "a\x00", + "ab", + "abb", + "abbr0", + "abbr ", + " abbr", + " a", + "acceptcharset", + "acceptCharset", + "accept_charset", + "h0", + "h1h2", + "h7", + "onClick", + "λ", + // The following string has the same hash (0xa1d7fab7) as "onmouseover". + "\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7", + } + for _, tc := range testCases { + got := Lookup([]byte(tc)) + if got != 0 { + t.Errorf("Lookup(%q): got %d, want 0", tc, got) + } + } +} + +func TestForeignObject(t *testing.T) { + const ( + afo = Foreignobject + afO = ForeignObject + sfo = "foreignobject" + sfO = "foreignObject" + ) + if got := Lookup([]byte(sfo)); got != afo { + t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo) + } + if got := Lookup([]byte(sfO)); got != afO { + t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO) + } + if got := afo.String(); got != sfo { + t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo) + } + if got := afO.String(); got != sfO { + t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO) + } +} + +func BenchmarkLookup(b *testing.B) { + sortedTable := make([]string, 0, len(table)) + for _, a := range table { + if a != 0 { + sortedTable = append(sortedTable, a.String()) + } + } + sort.Strings(sortedTable) + + x := make([][]byte, 1000) + for i := range x { + x[i] = []byte(sortedTable[i%len(sortedTable)]) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range x { + Lookup(s) + } + } +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/gen.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/gen.go new file mode 100644 index 00000000..6bfa8660 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/gen.go @@ -0,0 +1,648 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +// This program generates table.go and table_test.go. +// Invoke as +// +// go run gen.go |gofmt >table.go +// go run gen.go -test |gofmt >table_test.go + +import ( + "flag" + "fmt" + "math/rand" + "os" + "sort" + "strings" +) + +// identifier converts s to a Go exported identifier. +// It converts "div" to "Div" and "accept-charset" to "AcceptCharset". +func identifier(s string) string { + b := make([]byte, 0, len(s)) + cap := true + for _, c := range s { + if c == '-' { + cap = true + continue + } + if cap && 'a' <= c && c <= 'z' { + c -= 'a' - 'A' + } + cap = false + b = append(b, byte(c)) + } + return string(b) +} + +var test = flag.Bool("test", false, "generate table_test.go") + +func main() { + flag.Parse() + + var all []string + all = append(all, elements...) + all = append(all, attributes...) + all = append(all, eventHandlers...) + all = append(all, extra...) + sort.Strings(all) + + if *test { + fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n") + fmt.Printf("package atom\n\n") + fmt.Printf("var testAtomList = []string{\n") + for _, s := range all { + fmt.Printf("\t%q,\n", s) + } + fmt.Printf("}\n") + return + } + + // uniq - lists have dups + // compute max len too + maxLen := 0 + w := 0 + for _, s := range all { + if w == 0 || all[w-1] != s { + if maxLen < len(s) { + maxLen = len(s) + } + all[w] = s + w++ + } + } + all = all[:w] + + // Find hash that minimizes table size. + var best *table + for i := 0; i < 1000000; i++ { + if best != nil && 1<<(best.k-1) < len(all) { + break + } + h := rand.Uint32() + for k := uint(0); k <= 16; k++ { + if best != nil && k >= best.k { + break + } + var t table + if t.init(h, k, all) { + best = &t + break + } + } + } + if best == nil { + fmt.Fprintf(os.Stderr, "failed to construct string table\n") + os.Exit(1) + } + + // Lay out strings, using overlaps when possible. + layout := append([]string{}, all...) + + // Remove strings that are substrings of other strings + for changed := true; changed; { + changed = false + for i, s := range layout { + if s == "" { + continue + } + for j, t := range layout { + if i != j && t != "" && strings.Contains(s, t) { + changed = true + layout[j] = "" + } + } + } + } + + // Join strings where one suffix matches another prefix. + for { + // Find best i, j, k such that layout[i][len-k:] == layout[j][:k], + // maximizing overlap length k. + besti := -1 + bestj := -1 + bestk := 0 + for i, s := range layout { + if s == "" { + continue + } + for j, t := range layout { + if i == j { + continue + } + for k := bestk + 1; k <= len(s) && k <= len(t); k++ { + if s[len(s)-k:] == t[:k] { + besti = i + bestj = j + bestk = k + } + } + } + } + if bestk > 0 { + layout[besti] += layout[bestj][bestk:] + layout[bestj] = "" + continue + } + break + } + + text := strings.Join(layout, "") + + atom := map[string]uint32{} + for _, s := range all { + off := strings.Index(text, s) + if off < 0 { + panic("lost string " + s) + } + atom[s] = uint32(off<<8 | len(s)) + } + + // Generate the Go code. + fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n") + fmt.Printf("package atom\n\nconst (\n") + for _, s := range all { + fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s]) + } + fmt.Printf(")\n\n") + + fmt.Printf("const hash0 = %#x\n\n", best.h0) + fmt.Printf("const maxAtomLen = %d\n\n", maxLen) + + fmt.Printf("var table = [1<<%d]Atom{\n", best.k) + for i, s := range best.tab { + if s == "" { + continue + } + fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s) + } + fmt.Printf("}\n") + datasize := (1 << best.k) * 4 + + fmt.Printf("const atomText =\n") + textsize := len(text) + for len(text) > 60 { + fmt.Printf("\t%q +\n", text[:60]) + text = text[60:] + } + fmt.Printf("\t%q\n\n", text) + + fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize) +} + +type byLen []string + +func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) } +func (x byLen) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byLen) Len() int { return len(x) } + +// fnv computes the FNV hash with an arbitrary starting value h. +func fnv(h uint32, s string) uint32 { + for i := 0; i < len(s); i++ { + h ^= uint32(s[i]) + h *= 16777619 + } + return h +} + +// A table represents an attempt at constructing the lookup table. +// The lookup table uses cuckoo hashing, meaning that each string +// can be found in one of two positions. +type table struct { + h0 uint32 + k uint + mask uint32 + tab []string +} + +// hash returns the two hashes for s. +func (t *table) hash(s string) (h1, h2 uint32) { + h := fnv(t.h0, s) + h1 = h & t.mask + h2 = (h >> 16) & t.mask + return +} + +// init initializes the table with the given parameters. +// h0 is the initial hash value, +// k is the number of bits of hash value to use, and +// x is the list of strings to store in the table. +// init returns false if the table cannot be constructed. +func (t *table) init(h0 uint32, k uint, x []string) bool { + t.h0 = h0 + t.k = k + t.tab = make([]string, 1< len(t.tab) { + return false + } + s := t.tab[i] + h1, h2 := t.hash(s) + j := h1 + h2 - i + if t.tab[j] != "" && !t.push(j, depth+1) { + return false + } + t.tab[j] = s + return true +} + +// The lists of element names and attribute keys were taken from +// https://html.spec.whatwg.org/multipage/indices.html#index +// as of the "HTML Living Standard - Last Updated 21 February 2015" version. + +var elements = []string{ + "a", + "abbr", + "address", + "area", + "article", + "aside", + "audio", + "b", + "base", + "bdi", + "bdo", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "cite", + "code", + "col", + "colgroup", + "command", + "data", + "datalist", + "dd", + "del", + "details", + "dfn", + "dialog", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hgroup", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "kbd", + "keygen", + "label", + "legend", + "li", + "link", + "map", + "mark", + "menu", + "menuitem", + "meta", + "meter", + "nav", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "param", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "script", + "section", + "select", + "small", + "source", + "span", + "strong", + "style", + "sub", + "summary", + "sup", + "table", + "tbody", + "td", + "template", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "u", + "ul", + "var", + "video", + "wbr", +} + +// https://html.spec.whatwg.org/multipage/indices.html#attributes-3 + +var attributes = []string{ + "abbr", + "accept", + "accept-charset", + "accesskey", + "action", + "alt", + "async", + "autocomplete", + "autofocus", + "autoplay", + "challenge", + "charset", + "checked", + "cite", + "class", + "cols", + "colspan", + "command", + "content", + "contenteditable", + "contextmenu", + "controls", + "coords", + "crossorigin", + "data", + "datetime", + "default", + "defer", + "dir", + "dirname", + "disabled", + "download", + "draggable", + "dropzone", + "enctype", + "for", + "form", + "formaction", + "formenctype", + "formmethod", + "formnovalidate", + "formtarget", + "headers", + "height", + "hidden", + "high", + "href", + "hreflang", + "http-equiv", + "icon", + "id", + "inputmode", + "ismap", + "itemid", + "itemprop", + "itemref", + "itemscope", + "itemtype", + "keytype", + "kind", + "label", + "lang", + "list", + "loop", + "low", + "manifest", + "max", + "maxlength", + "media", + "mediagroup", + "method", + "min", + "minlength", + "multiple", + "muted", + "name", + "novalidate", + "open", + "optimum", + "pattern", + "ping", + "placeholder", + "poster", + "preload", + "radiogroup", + "readonly", + "rel", + "required", + "reversed", + "rows", + "rowspan", + "sandbox", + "spellcheck", + "scope", + "scoped", + "seamless", + "selected", + "shape", + "size", + "sizes", + "sortable", + "sorted", + "span", + "src", + "srcdoc", + "srclang", + "start", + "step", + "style", + "tabindex", + "target", + "title", + "translate", + "type", + "typemustmatch", + "usemap", + "value", + "width", + "wrap", +} + +var eventHandlers = []string{ + "onabort", + "onautocomplete", + "onautocompleteerror", + "onafterprint", + "onbeforeprint", + "onbeforeunload", + "onblur", + "oncancel", + "oncanplay", + "oncanplaythrough", + "onchange", + "onclick", + "onclose", + "oncontextmenu", + "oncuechange", + "ondblclick", + "ondrag", + "ondragend", + "ondragenter", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onended", + "onerror", + "onfocus", + "onhashchange", + "oninput", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeyup", + "onlanguagechange", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadstart", + "onmessage", + "onmousedown", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onoffline", + "ononline", + "onpagehide", + "onpageshow", + "onpause", + "onplay", + "onplaying", + "onpopstate", + "onprogress", + "onratechange", + "onreset", + "onresize", + "onscroll", + "onseeked", + "onseeking", + "onselect", + "onshow", + "onsort", + "onstalled", + "onstorage", + "onsubmit", + "onsuspend", + "ontimeupdate", + "ontoggle", + "onunload", + "onvolumechange", + "onwaiting", +} + +// extra are ad-hoc values not covered by any of the lists above. +var extra = []string{ + "align", + "annotation", + "annotation-xml", + "applet", + "basefont", + "bgsound", + "big", + "blink", + "center", + "color", + "desc", + "face", + "font", + "foreignObject", // HTML is case-insensitive, but SVG-embedded-in-HTML is case-sensitive. + "foreignobject", + "frame", + "frameset", + "image", + "isindex", + "listing", + "malignmark", + "marquee", + "math", + "mglyph", + "mi", + "mn", + "mo", + "ms", + "mtext", + "nobr", + "noembed", + "noframes", + "plaintext", + "prompt", + "public", + "spacer", + "strike", + "svg", + "system", + "tt", + "xmp", +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table.go new file mode 100644 index 00000000..2605ba31 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table.go @@ -0,0 +1,713 @@ +// generated by go run gen.go; DO NOT EDIT + +package atom + +const ( + A Atom = 0x1 + Abbr Atom = 0x4 + Accept Atom = 0x2106 + AcceptCharset Atom = 0x210e + Accesskey Atom = 0x3309 + Action Atom = 0x1f606 + Address Atom = 0x4f307 + Align Atom = 0x1105 + Alt Atom = 0x4503 + Annotation Atom = 0x1670a + AnnotationXml Atom = 0x1670e + Applet Atom = 0x2b306 + Area Atom = 0x2fa04 + Article Atom = 0x38807 + Aside Atom = 0x8305 + Async Atom = 0x7b05 + Audio Atom = 0xa605 + Autocomplete Atom = 0x1fc0c + Autofocus Atom = 0xb309 + Autoplay Atom = 0xce08 + B Atom = 0x101 + Base Atom = 0xd604 + Basefont Atom = 0xd608 + Bdi Atom = 0x1a03 + Bdo Atom = 0xe703 + Bgsound Atom = 0x11807 + Big Atom = 0x12403 + Blink Atom = 0x12705 + Blockquote Atom = 0x12c0a + Body Atom = 0x2f04 + Br Atom = 0x202 + Button Atom = 0x13606 + Canvas Atom = 0x7f06 + Caption Atom = 0x1bb07 + Center Atom = 0x5b506 + Challenge Atom = 0x21f09 + Charset Atom = 0x2807 + Checked Atom = 0x32807 + Cite Atom = 0x3c804 + Class Atom = 0x4de05 + Code Atom = 0x14904 + Col Atom = 0x15003 + Colgroup Atom = 0x15008 + Color Atom = 0x15d05 + Cols Atom = 0x16204 + Colspan Atom = 0x16207 + Command Atom = 0x17507 + Content Atom = 0x42307 + Contenteditable Atom = 0x4230f + Contextmenu Atom = 0x3310b + Controls Atom = 0x18808 + Coords Atom = 0x19406 + Crossorigin Atom = 0x19f0b + Data Atom = 0x44a04 + Datalist Atom = 0x44a08 + Datetime Atom = 0x23c08 + Dd Atom = 0x26702 + Default Atom = 0x8607 + Defer Atom = 0x14b05 + Del Atom = 0x3ef03 + Desc Atom = 0x4db04 + Details Atom = 0x4807 + Dfn Atom = 0x6103 + Dialog Atom = 0x1b06 + Dir Atom = 0x6903 + Dirname Atom = 0x6907 + Disabled Atom = 0x10c08 + Div Atom = 0x11303 + Dl Atom = 0x11e02 + Download Atom = 0x40008 + Draggable Atom = 0x17b09 + Dropzone Atom = 0x39108 + Dt Atom = 0x50902 + Em Atom = 0x6502 + Embed Atom = 0x6505 + Enctype Atom = 0x21107 + Face Atom = 0x5b304 + Fieldset Atom = 0x1b008 + Figcaption Atom = 0x1b80a + Figure Atom = 0x1cc06 + Font Atom = 0xda04 + Footer Atom = 0x8d06 + For Atom = 0x1d803 + ForeignObject Atom = 0x1d80d + Foreignobject Atom = 0x1e50d + Form Atom = 0x1f204 + Formaction Atom = 0x1f20a + Formenctype Atom = 0x20d0b + Formmethod Atom = 0x2280a + Formnovalidate Atom = 0x2320e + Formtarget Atom = 0x2470a + Frame Atom = 0x9a05 + Frameset Atom = 0x9a08 + H1 Atom = 0x26e02 + H2 Atom = 0x29402 + H3 Atom = 0x2a702 + H4 Atom = 0x2e902 + H5 Atom = 0x2f302 + H6 Atom = 0x50b02 + Head Atom = 0x2d504 + Header Atom = 0x2d506 + Headers Atom = 0x2d507 + Height Atom = 0x25106 + Hgroup Atom = 0x25906 + Hidden Atom = 0x26506 + High Atom = 0x26b04 + Hr Atom = 0x27002 + Href Atom = 0x27004 + Hreflang Atom = 0x27008 + Html Atom = 0x25504 + HttpEquiv Atom = 0x2780a + I Atom = 0x601 + Icon Atom = 0x42204 + Id Atom = 0x8502 + Iframe Atom = 0x29606 + Image Atom = 0x29c05 + Img Atom = 0x2a103 + Input Atom = 0x3e805 + Inputmode Atom = 0x3e809 + Ins Atom = 0x1a803 + Isindex Atom = 0x2a907 + Ismap Atom = 0x2b005 + Itemid Atom = 0x33c06 + Itemprop Atom = 0x3c908 + Itemref Atom = 0x5ad07 + Itemscope Atom = 0x2b909 + Itemtype Atom = 0x2c308 + Kbd Atom = 0x1903 + Keygen Atom = 0x3906 + Keytype Atom = 0x53707 + Kind Atom = 0x10904 + Label Atom = 0xf005 + Lang Atom = 0x27404 + Legend Atom = 0x18206 + Li Atom = 0x1202 + Link Atom = 0x12804 + List Atom = 0x44e04 + Listing Atom = 0x44e07 + Loop Atom = 0xf404 + Low Atom = 0x11f03 + Malignmark Atom = 0x100a + Manifest Atom = 0x5f108 + Map Atom = 0x2b203 + Mark Atom = 0x1604 + Marquee Atom = 0x2cb07 + Math Atom = 0x2d204 + Max Atom = 0x2e103 + Maxlength Atom = 0x2e109 + Media Atom = 0x6e05 + Mediagroup Atom = 0x6e0a + Menu Atom = 0x33804 + Menuitem Atom = 0x33808 + Meta Atom = 0x45d04 + Meter Atom = 0x24205 + Method Atom = 0x22c06 + Mglyph Atom = 0x2a206 + Mi Atom = 0x2eb02 + Min Atom = 0x2eb03 + Minlength Atom = 0x2eb09 + Mn Atom = 0x23502 + Mo Atom = 0x3ed02 + Ms Atom = 0x2bc02 + Mtext Atom = 0x2f505 + Multiple Atom = 0x30308 + Muted Atom = 0x30b05 + Name Atom = 0x6c04 + Nav Atom = 0x3e03 + Nobr Atom = 0x5704 + Noembed Atom = 0x6307 + Noframes Atom = 0x9808 + Noscript Atom = 0x3d208 + Novalidate Atom = 0x2360a + Object Atom = 0x1ec06 + Ol Atom = 0xc902 + Onabort Atom = 0x13a07 + Onafterprint Atom = 0x1c00c + Onautocomplete Atom = 0x1fa0e + Onautocompleteerror Atom = 0x1fa13 + Onbeforeprint Atom = 0x6040d + Onbeforeunload Atom = 0x4e70e + Onblur Atom = 0xaa06 + Oncancel Atom = 0xe908 + Oncanplay Atom = 0x28509 + Oncanplaythrough Atom = 0x28510 + Onchange Atom = 0x3a708 + Onclick Atom = 0x31007 + Onclose Atom = 0x31707 + Oncontextmenu Atom = 0x32f0d + Oncuechange Atom = 0x3420b + Ondblclick Atom = 0x34d0a + Ondrag Atom = 0x35706 + Ondragend Atom = 0x35709 + Ondragenter Atom = 0x3600b + Ondragleave Atom = 0x36b0b + Ondragover Atom = 0x3760a + Ondragstart Atom = 0x3800b + Ondrop Atom = 0x38f06 + Ondurationchange Atom = 0x39f10 + Onemptied Atom = 0x39609 + Onended Atom = 0x3af07 + Onerror Atom = 0x3b607 + Onfocus Atom = 0x3bd07 + Onhashchange Atom = 0x3da0c + Oninput Atom = 0x3e607 + Oninvalid Atom = 0x3f209 + Onkeydown Atom = 0x3fb09 + Onkeypress Atom = 0x4080a + Onkeyup Atom = 0x41807 + Onlanguagechange Atom = 0x43210 + Onload Atom = 0x44206 + Onloadeddata Atom = 0x4420c + Onloadedmetadata Atom = 0x45510 + Onloadstart Atom = 0x46b0b + Onmessage Atom = 0x47609 + Onmousedown Atom = 0x47f0b + Onmousemove Atom = 0x48a0b + Onmouseout Atom = 0x4950a + Onmouseover Atom = 0x4a20b + Onmouseup Atom = 0x4ad09 + Onmousewheel Atom = 0x4b60c + Onoffline Atom = 0x4c209 + Ononline Atom = 0x4cb08 + Onpagehide Atom = 0x4d30a + Onpageshow Atom = 0x4fe0a + Onpause Atom = 0x50d07 + Onplay Atom = 0x51706 + Onplaying Atom = 0x51709 + Onpopstate Atom = 0x5200a + Onprogress Atom = 0x52a0a + Onratechange Atom = 0x53e0c + Onreset Atom = 0x54a07 + Onresize Atom = 0x55108 + Onscroll Atom = 0x55f08 + Onseeked Atom = 0x56708 + Onseeking Atom = 0x56f09 + Onselect Atom = 0x57808 + Onshow Atom = 0x58206 + Onsort Atom = 0x58b06 + Onstalled Atom = 0x59509 + Onstorage Atom = 0x59e09 + Onsubmit Atom = 0x5a708 + Onsuspend Atom = 0x5bb09 + Ontimeupdate Atom = 0xdb0c + Ontoggle Atom = 0x5c408 + Onunload Atom = 0x5cc08 + Onvolumechange Atom = 0x5d40e + Onwaiting Atom = 0x5e209 + Open Atom = 0x3cf04 + Optgroup Atom = 0xf608 + Optimum Atom = 0x5eb07 + Option Atom = 0x60006 + Output Atom = 0x49c06 + P Atom = 0xc01 + Param Atom = 0xc05 + Pattern Atom = 0x5107 + Ping Atom = 0x7704 + Placeholder Atom = 0xc30b + Plaintext Atom = 0xfd09 + Poster Atom = 0x15706 + Pre Atom = 0x25e03 + Preload Atom = 0x25e07 + Progress Atom = 0x52c08 + Prompt Atom = 0x5fa06 + Public Atom = 0x41e06 + Q Atom = 0x13101 + Radiogroup Atom = 0x30a + Readonly Atom = 0x2fb08 + Rel Atom = 0x25f03 + Required Atom = 0x1d008 + Reversed Atom = 0x5a08 + Rows Atom = 0x9204 + Rowspan Atom = 0x9207 + Rp Atom = 0x1c602 + Rt Atom = 0x13f02 + Ruby Atom = 0xaf04 + S Atom = 0x2c01 + Samp Atom = 0x4e04 + Sandbox Atom = 0xbb07 + Scope Atom = 0x2bd05 + Scoped Atom = 0x2bd06 + Script Atom = 0x3d406 + Seamless Atom = 0x31c08 + Section Atom = 0x4e207 + Select Atom = 0x57a06 + Selected Atom = 0x57a08 + Shape Atom = 0x4f905 + Size Atom = 0x55504 + Sizes Atom = 0x55505 + Small Atom = 0x18f05 + Sortable Atom = 0x58d08 + Sorted Atom = 0x19906 + Source Atom = 0x1aa06 + Spacer Atom = 0x2db06 + Span Atom = 0x9504 + Spellcheck Atom = 0x3230a + Src Atom = 0x3c303 + Srcdoc Atom = 0x3c306 + Srclang Atom = 0x41107 + Start Atom = 0x38605 + Step Atom = 0x5f704 + Strike Atom = 0x53306 + Strong Atom = 0x55906 + Style Atom = 0x61105 + Sub Atom = 0x5a903 + Summary Atom = 0x61607 + Sup Atom = 0x61d03 + Svg Atom = 0x62003 + System Atom = 0x62306 + Tabindex Atom = 0x46308 + Table Atom = 0x42d05 + Target Atom = 0x24b06 + Tbody Atom = 0x2e05 + Td Atom = 0x4702 + Template Atom = 0x62608 + Textarea Atom = 0x2f608 + Tfoot Atom = 0x8c05 + Th Atom = 0x22e02 + Thead Atom = 0x2d405 + Time Atom = 0xdd04 + Title Atom = 0xa105 + Tr Atom = 0x10502 + Track Atom = 0x10505 + Translate Atom = 0x14009 + Tt Atom = 0x5302 + Type Atom = 0x21404 + Typemustmatch Atom = 0x2140d + U Atom = 0xb01 + Ul Atom = 0x8a02 + Usemap Atom = 0x51106 + Value Atom = 0x4005 + Var Atom = 0x11503 + Video Atom = 0x28105 + Wbr Atom = 0x12103 + Width Atom = 0x50705 + Wrap Atom = 0x58704 + Xmp Atom = 0xc103 +) + +const hash0 = 0xc17da63e + +const maxAtomLen = 19 + +var table = [1 << 9]Atom{ + 0x1: 0x48a0b, // onmousemove + 0x2: 0x5e209, // onwaiting + 0x3: 0x1fa13, // onautocompleteerror + 0x4: 0x5fa06, // prompt + 0x7: 0x5eb07, // optimum + 0x8: 0x1604, // mark + 0xa: 0x5ad07, // itemref + 0xb: 0x4fe0a, // onpageshow + 0xc: 0x57a06, // select + 0xd: 0x17b09, // draggable + 0xe: 0x3e03, // nav + 0xf: 0x17507, // command + 0x11: 0xb01, // u + 0x14: 0x2d507, // headers + 0x15: 0x44a08, // datalist + 0x17: 0x4e04, // samp + 0x1a: 0x3fb09, // onkeydown + 0x1b: 0x55f08, // onscroll + 0x1c: 0x15003, // col + 0x20: 0x3c908, // itemprop + 0x21: 0x2780a, // http-equiv + 0x22: 0x61d03, // sup + 0x24: 0x1d008, // required + 0x2b: 0x25e07, // preload + 0x2c: 0x6040d, // onbeforeprint + 0x2d: 0x3600b, // ondragenter + 0x2e: 0x50902, // dt + 0x2f: 0x5a708, // onsubmit + 0x30: 0x27002, // hr + 0x31: 0x32f0d, // oncontextmenu + 0x33: 0x29c05, // image + 0x34: 0x50d07, // onpause + 0x35: 0x25906, // hgroup + 0x36: 0x7704, // ping + 0x37: 0x57808, // onselect + 0x3a: 0x11303, // div + 0x3b: 0x1fa0e, // onautocomplete + 0x40: 0x2eb02, // mi + 0x41: 0x31c08, // seamless + 0x42: 0x2807, // charset + 0x43: 0x8502, // id + 0x44: 0x5200a, // onpopstate + 0x45: 0x3ef03, // del + 0x46: 0x2cb07, // marquee + 0x47: 0x3309, // accesskey + 0x49: 0x8d06, // footer + 0x4a: 0x44e04, // list + 0x4b: 0x2b005, // ismap + 0x51: 0x33804, // menu + 0x52: 0x2f04, // body + 0x55: 0x9a08, // frameset + 0x56: 0x54a07, // onreset + 0x57: 0x12705, // blink + 0x58: 0xa105, // title + 0x59: 0x38807, // article + 0x5b: 0x22e02, // th + 0x5d: 0x13101, // q + 0x5e: 0x3cf04, // open + 0x5f: 0x2fa04, // area + 0x61: 0x44206, // onload + 0x62: 0xda04, // font + 0x63: 0xd604, // base + 0x64: 0x16207, // colspan + 0x65: 0x53707, // keytype + 0x66: 0x11e02, // dl + 0x68: 0x1b008, // fieldset + 0x6a: 0x2eb03, // min + 0x6b: 0x11503, // var + 0x6f: 0x2d506, // header + 0x70: 0x13f02, // rt + 0x71: 0x15008, // colgroup + 0x72: 0x23502, // mn + 0x74: 0x13a07, // onabort + 0x75: 0x3906, // keygen + 0x76: 0x4c209, // onoffline + 0x77: 0x21f09, // challenge + 0x78: 0x2b203, // map + 0x7a: 0x2e902, // h4 + 0x7b: 0x3b607, // onerror + 0x7c: 0x2e109, // maxlength + 0x7d: 0x2f505, // mtext + 0x7e: 0xbb07, // sandbox + 0x7f: 0x58b06, // onsort + 0x80: 0x100a, // malignmark + 0x81: 0x45d04, // meta + 0x82: 0x7b05, // async + 0x83: 0x2a702, // h3 + 0x84: 0x26702, // dd + 0x85: 0x27004, // href + 0x86: 0x6e0a, // mediagroup + 0x87: 0x19406, // coords + 0x88: 0x41107, // srclang + 0x89: 0x34d0a, // ondblclick + 0x8a: 0x4005, // value + 0x8c: 0xe908, // oncancel + 0x8e: 0x3230a, // spellcheck + 0x8f: 0x9a05, // frame + 0x91: 0x12403, // big + 0x94: 0x1f606, // action + 0x95: 0x6903, // dir + 0x97: 0x2fb08, // readonly + 0x99: 0x42d05, // table + 0x9a: 0x61607, // summary + 0x9b: 0x12103, // wbr + 0x9c: 0x30a, // radiogroup + 0x9d: 0x6c04, // name + 0x9f: 0x62306, // system + 0xa1: 0x15d05, // color + 0xa2: 0x7f06, // canvas + 0xa3: 0x25504, // html + 0xa5: 0x56f09, // onseeking + 0xac: 0x4f905, // shape + 0xad: 0x25f03, // rel + 0xae: 0x28510, // oncanplaythrough + 0xaf: 0x3760a, // ondragover + 0xb0: 0x62608, // template + 0xb1: 0x1d80d, // foreignObject + 0xb3: 0x9204, // rows + 0xb6: 0x44e07, // listing + 0xb7: 0x49c06, // output + 0xb9: 0x3310b, // contextmenu + 0xbb: 0x11f03, // low + 0xbc: 0x1c602, // rp + 0xbd: 0x5bb09, // onsuspend + 0xbe: 0x13606, // button + 0xbf: 0x4db04, // desc + 0xc1: 0x4e207, // section + 0xc2: 0x52a0a, // onprogress + 0xc3: 0x59e09, // onstorage + 0xc4: 0x2d204, // math + 0xc5: 0x4503, // alt + 0xc7: 0x8a02, // ul + 0xc8: 0x5107, // pattern + 0xc9: 0x4b60c, // onmousewheel + 0xca: 0x35709, // ondragend + 0xcb: 0xaf04, // ruby + 0xcc: 0xc01, // p + 0xcd: 0x31707, // onclose + 0xce: 0x24205, // meter + 0xcf: 0x11807, // bgsound + 0xd2: 0x25106, // height + 0xd4: 0x101, // b + 0xd5: 0x2c308, // itemtype + 0xd8: 0x1bb07, // caption + 0xd9: 0x10c08, // disabled + 0xdb: 0x33808, // menuitem + 0xdc: 0x62003, // svg + 0xdd: 0x18f05, // small + 0xde: 0x44a04, // data + 0xe0: 0x4cb08, // ononline + 0xe1: 0x2a206, // mglyph + 0xe3: 0x6505, // embed + 0xe4: 0x10502, // tr + 0xe5: 0x46b0b, // onloadstart + 0xe7: 0x3c306, // srcdoc + 0xeb: 0x5c408, // ontoggle + 0xed: 0xe703, // bdo + 0xee: 0x4702, // td + 0xef: 0x8305, // aside + 0xf0: 0x29402, // h2 + 0xf1: 0x52c08, // progress + 0xf2: 0x12c0a, // blockquote + 0xf4: 0xf005, // label + 0xf5: 0x601, // i + 0xf7: 0x9207, // rowspan + 0xfb: 0x51709, // onplaying + 0xfd: 0x2a103, // img + 0xfe: 0xf608, // optgroup + 0xff: 0x42307, // content + 0x101: 0x53e0c, // onratechange + 0x103: 0x3da0c, // onhashchange + 0x104: 0x4807, // details + 0x106: 0x40008, // download + 0x109: 0x14009, // translate + 0x10b: 0x4230f, // contenteditable + 0x10d: 0x36b0b, // ondragleave + 0x10e: 0x2106, // accept + 0x10f: 0x57a08, // selected + 0x112: 0x1f20a, // formaction + 0x113: 0x5b506, // center + 0x115: 0x45510, // onloadedmetadata + 0x116: 0x12804, // link + 0x117: 0xdd04, // time + 0x118: 0x19f0b, // crossorigin + 0x119: 0x3bd07, // onfocus + 0x11a: 0x58704, // wrap + 0x11b: 0x42204, // icon + 0x11d: 0x28105, // video + 0x11e: 0x4de05, // class + 0x121: 0x5d40e, // onvolumechange + 0x122: 0xaa06, // onblur + 0x123: 0x2b909, // itemscope + 0x124: 0x61105, // style + 0x127: 0x41e06, // public + 0x129: 0x2320e, // formnovalidate + 0x12a: 0x58206, // onshow + 0x12c: 0x51706, // onplay + 0x12d: 0x3c804, // cite + 0x12e: 0x2bc02, // ms + 0x12f: 0xdb0c, // ontimeupdate + 0x130: 0x10904, // kind + 0x131: 0x2470a, // formtarget + 0x135: 0x3af07, // onended + 0x136: 0x26506, // hidden + 0x137: 0x2c01, // s + 0x139: 0x2280a, // formmethod + 0x13a: 0x3e805, // input + 0x13c: 0x50b02, // h6 + 0x13d: 0xc902, // ol + 0x13e: 0x3420b, // oncuechange + 0x13f: 0x1e50d, // foreignobject + 0x143: 0x4e70e, // onbeforeunload + 0x144: 0x2bd05, // scope + 0x145: 0x39609, // onemptied + 0x146: 0x14b05, // defer + 0x147: 0xc103, // xmp + 0x148: 0x39f10, // ondurationchange + 0x149: 0x1903, // kbd + 0x14c: 0x47609, // onmessage + 0x14d: 0x60006, // option + 0x14e: 0x2eb09, // minlength + 0x14f: 0x32807, // checked + 0x150: 0xce08, // autoplay + 0x152: 0x202, // br + 0x153: 0x2360a, // novalidate + 0x156: 0x6307, // noembed + 0x159: 0x31007, // onclick + 0x15a: 0x47f0b, // onmousedown + 0x15b: 0x3a708, // onchange + 0x15e: 0x3f209, // oninvalid + 0x15f: 0x2bd06, // scoped + 0x160: 0x18808, // controls + 0x161: 0x30b05, // muted + 0x162: 0x58d08, // sortable + 0x163: 0x51106, // usemap + 0x164: 0x1b80a, // figcaption + 0x165: 0x35706, // ondrag + 0x166: 0x26b04, // high + 0x168: 0x3c303, // src + 0x169: 0x15706, // poster + 0x16b: 0x1670e, // annotation-xml + 0x16c: 0x5f704, // step + 0x16d: 0x4, // abbr + 0x16e: 0x1b06, // dialog + 0x170: 0x1202, // li + 0x172: 0x3ed02, // mo + 0x175: 0x1d803, // for + 0x176: 0x1a803, // ins + 0x178: 0x55504, // size + 0x179: 0x43210, // onlanguagechange + 0x17a: 0x8607, // default + 0x17b: 0x1a03, // bdi + 0x17c: 0x4d30a, // onpagehide + 0x17d: 0x6907, // dirname + 0x17e: 0x21404, // type + 0x17f: 0x1f204, // form + 0x181: 0x28509, // oncanplay + 0x182: 0x6103, // dfn + 0x183: 0x46308, // tabindex + 0x186: 0x6502, // em + 0x187: 0x27404, // lang + 0x189: 0x39108, // dropzone + 0x18a: 0x4080a, // onkeypress + 0x18b: 0x23c08, // datetime + 0x18c: 0x16204, // cols + 0x18d: 0x1, // a + 0x18e: 0x4420c, // onloadeddata + 0x190: 0xa605, // audio + 0x192: 0x2e05, // tbody + 0x193: 0x22c06, // method + 0x195: 0xf404, // loop + 0x196: 0x29606, // iframe + 0x198: 0x2d504, // head + 0x19e: 0x5f108, // manifest + 0x19f: 0xb309, // autofocus + 0x1a0: 0x14904, // code + 0x1a1: 0x55906, // strong + 0x1a2: 0x30308, // multiple + 0x1a3: 0xc05, // param + 0x1a6: 0x21107, // enctype + 0x1a7: 0x5b304, // face + 0x1a8: 0xfd09, // plaintext + 0x1a9: 0x26e02, // h1 + 0x1aa: 0x59509, // onstalled + 0x1ad: 0x3d406, // script + 0x1ae: 0x2db06, // spacer + 0x1af: 0x55108, // onresize + 0x1b0: 0x4a20b, // onmouseover + 0x1b1: 0x5cc08, // onunload + 0x1b2: 0x56708, // onseeked + 0x1b4: 0x2140d, // typemustmatch + 0x1b5: 0x1cc06, // figure + 0x1b6: 0x4950a, // onmouseout + 0x1b7: 0x25e03, // pre + 0x1b8: 0x50705, // width + 0x1b9: 0x19906, // sorted + 0x1bb: 0x5704, // nobr + 0x1be: 0x5302, // tt + 0x1bf: 0x1105, // align + 0x1c0: 0x3e607, // oninput + 0x1c3: 0x41807, // onkeyup + 0x1c6: 0x1c00c, // onafterprint + 0x1c7: 0x210e, // accept-charset + 0x1c8: 0x33c06, // itemid + 0x1c9: 0x3e809, // inputmode + 0x1cb: 0x53306, // strike + 0x1cc: 0x5a903, // sub + 0x1cd: 0x10505, // track + 0x1ce: 0x38605, // start + 0x1d0: 0xd608, // basefont + 0x1d6: 0x1aa06, // source + 0x1d7: 0x18206, // legend + 0x1d8: 0x2d405, // thead + 0x1da: 0x8c05, // tfoot + 0x1dd: 0x1ec06, // object + 0x1de: 0x6e05, // media + 0x1df: 0x1670a, // annotation + 0x1e0: 0x20d0b, // formenctype + 0x1e2: 0x3d208, // noscript + 0x1e4: 0x55505, // sizes + 0x1e5: 0x1fc0c, // autocomplete + 0x1e6: 0x9504, // span + 0x1e7: 0x9808, // noframes + 0x1e8: 0x24b06, // target + 0x1e9: 0x38f06, // ondrop + 0x1ea: 0x2b306, // applet + 0x1ec: 0x5a08, // reversed + 0x1f0: 0x2a907, // isindex + 0x1f3: 0x27008, // hreflang + 0x1f5: 0x2f302, // h5 + 0x1f6: 0x4f307, // address + 0x1fa: 0x2e103, // max + 0x1fb: 0xc30b, // placeholder + 0x1fc: 0x2f608, // textarea + 0x1fe: 0x4ad09, // onmouseup + 0x1ff: 0x3800b, // ondragstart +} + +const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" + + "genavaluealtdetailsampatternobreversedfnoembedirnamediagroup" + + "ingasyncanvasidefaultfooterowspanoframesetitleaudionblurubya" + + "utofocusandboxmplaceholderautoplaybasefontimeupdatebdoncance" + + "labelooptgrouplaintextrackindisabledivarbgsoundlowbrbigblink" + + "blockquotebuttonabortranslatecodefercolgroupostercolorcolspa" + + "nnotation-xmlcommandraggablegendcontrolsmallcoordsortedcross" + + "originsourcefieldsetfigcaptionafterprintfigurequiredforeignO" + + "bjectforeignobjectformactionautocompleteerrorformenctypemust" + + "matchallengeformmethodformnovalidatetimeterformtargetheightm" + + "lhgroupreloadhiddenhigh1hreflanghttp-equivideoncanplaythroug" + + "h2iframeimageimglyph3isindexismappletitemscopeditemtypemarqu" + + "eematheaderspacermaxlength4minlength5mtextareadonlymultiplem" + + "utedonclickoncloseamlesspellcheckedoncontextmenuitemidoncuec" + + "hangeondblclickondragendondragenterondragleaveondragoverondr" + + "agstarticleondropzonemptiedondurationchangeonendedonerroronf" + + "ocusrcdocitempropenoscriptonhashchangeoninputmodeloninvalido" + + "nkeydownloadonkeypressrclangonkeyupublicontenteditableonlang" + + "uagechangeonloadeddatalistingonloadedmetadatabindexonloadsta" + + "rtonmessageonmousedownonmousemoveonmouseoutputonmouseoveronm" + + "ouseuponmousewheelonofflineononlineonpagehidesclassectionbef" + + "oreunloaddresshapeonpageshowidth6onpausemaponplayingonpopsta" + + "teonprogresstrikeytypeonratechangeonresetonresizestrongonscr" + + "ollonseekedonseekingonselectedonshowraponsortableonstalledon" + + "storageonsubmitemrefacenteronsuspendontoggleonunloadonvolume" + + "changeonwaitingoptimumanifestepromptoptionbeforeprintstylesu" + + "mmarysupsvgsystemplate" diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table_test.go new file mode 100644 index 00000000..0f2ecce4 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/atom/table_test.go @@ -0,0 +1,351 @@ +// generated by go run gen.go -test; DO NOT EDIT + +package atom + +var testAtomList = []string{ + "a", + "abbr", + "abbr", + "accept", + "accept-charset", + "accesskey", + "action", + "address", + "align", + "alt", + "annotation", + "annotation-xml", + "applet", + "area", + "article", + "aside", + "async", + "audio", + "autocomplete", + "autofocus", + "autoplay", + "b", + "base", + "basefont", + "bdi", + "bdo", + "bgsound", + "big", + "blink", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "center", + "challenge", + "charset", + "checked", + "cite", + "cite", + "class", + "code", + "col", + "colgroup", + "color", + "cols", + "colspan", + "command", + "command", + "content", + "contenteditable", + "contextmenu", + "controls", + "coords", + "crossorigin", + "data", + "data", + "datalist", + "datetime", + "dd", + "default", + "defer", + "del", + "desc", + "details", + "dfn", + "dialog", + "dir", + "dirname", + "disabled", + "div", + "dl", + "download", + "draggable", + "dropzone", + "dt", + "em", + "embed", + "enctype", + "face", + "fieldset", + "figcaption", + "figure", + "font", + "footer", + "for", + "foreignObject", + "foreignobject", + "form", + "form", + "formaction", + "formenctype", + "formmethod", + "formnovalidate", + "formtarget", + "frame", + "frameset", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "headers", + "height", + "hgroup", + "hidden", + "high", + "hr", + "href", + "hreflang", + "html", + "http-equiv", + "i", + "icon", + "id", + "iframe", + "image", + "img", + "input", + "inputmode", + "ins", + "isindex", + "ismap", + "itemid", + "itemprop", + "itemref", + "itemscope", + "itemtype", + "kbd", + "keygen", + "keytype", + "kind", + "label", + "label", + "lang", + "legend", + "li", + "link", + "list", + "listing", + "loop", + "low", + "malignmark", + "manifest", + "map", + "mark", + "marquee", + "math", + "max", + "maxlength", + "media", + "mediagroup", + "menu", + "menuitem", + "meta", + "meter", + "method", + "mglyph", + "mi", + "min", + "minlength", + "mn", + "mo", + "ms", + "mtext", + "multiple", + "muted", + "name", + "nav", + "nobr", + "noembed", + "noframes", + "noscript", + "novalidate", + "object", + "ol", + "onabort", + "onafterprint", + "onautocomplete", + "onautocompleteerror", + "onbeforeprint", + "onbeforeunload", + "onblur", + "oncancel", + "oncanplay", + "oncanplaythrough", + "onchange", + "onclick", + "onclose", + "oncontextmenu", + "oncuechange", + "ondblclick", + "ondrag", + "ondragend", + "ondragenter", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onended", + "onerror", + "onfocus", + "onhashchange", + "oninput", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeyup", + "onlanguagechange", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadstart", + "onmessage", + "onmousedown", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onoffline", + "ononline", + "onpagehide", + "onpageshow", + "onpause", + "onplay", + "onplaying", + "onpopstate", + "onprogress", + "onratechange", + "onreset", + "onresize", + "onscroll", + "onseeked", + "onseeking", + "onselect", + "onshow", + "onsort", + "onstalled", + "onstorage", + "onsubmit", + "onsuspend", + "ontimeupdate", + "ontoggle", + "onunload", + "onvolumechange", + "onwaiting", + "open", + "optgroup", + "optimum", + "option", + "output", + "p", + "param", + "pattern", + "ping", + "placeholder", + "plaintext", + "poster", + "pre", + "preload", + "progress", + "prompt", + "public", + "q", + "radiogroup", + "readonly", + "rel", + "required", + "reversed", + "rows", + "rowspan", + "rp", + "rt", + "ruby", + "s", + "samp", + "sandbox", + "scope", + "scoped", + "script", + "seamless", + "section", + "select", + "selected", + "shape", + "size", + "sizes", + "small", + "sortable", + "sorted", + "source", + "spacer", + "span", + "span", + "spellcheck", + "src", + "srcdoc", + "srclang", + "start", + "step", + "strike", + "strong", + "style", + "style", + "sub", + "summary", + "sup", + "svg", + "system", + "tabindex", + "table", + "target", + "tbody", + "td", + "template", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "title", + "tr", + "track", + "translate", + "tt", + "type", + "typemustmatch", + "u", + "ul", + "usemap", + "value", + "var", + "video", + "wbr", + "width", + "wrap", + "xmp", +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset.go new file mode 100644 index 00000000..13bed159 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset.go @@ -0,0 +1,257 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package charset provides common text encodings for HTML documents. +// +// The mapping from encoding labels to encodings is defined at +// https://encoding.spec.whatwg.org/. +package charset // import "golang.org/x/net/html/charset" + +import ( + "bytes" + "fmt" + "io" + "mime" + "strings" + "unicode/utf8" + + "golang.org/x/net/html" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/encoding/htmlindex" + "golang.org/x/text/transform" +) + +// Lookup returns the encoding with the specified label, and its canonical +// name. It returns nil and the empty string if label is not one of the +// standard encodings for HTML. Matching is case-insensitive and ignores +// leading and trailing whitespace. Encoders will use HTML escape sequences for +// runes that are not supported by the character set. +func Lookup(label string) (e encoding.Encoding, name string) { + e, err := htmlindex.Get(label) + if err != nil { + return nil, "" + } + name, _ = htmlindex.Name(e) + return &htmlEncoding{e}, name +} + +type htmlEncoding struct{ encoding.Encoding } + +func (h *htmlEncoding) NewEncoder() *encoding.Encoder { + // HTML requires a non-terminating legacy encoder. We use HTML escapes to + // substitute unsupported code points. + return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder()) +} + +// DetermineEncoding determines the encoding of an HTML document by examining +// up to the first 1024 bytes of content and the declared Content-Type. +// +// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding +func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) { + if len(content) > 1024 { + content = content[:1024] + } + + for _, b := range boms { + if bytes.HasPrefix(content, b.bom) { + e, name = Lookup(b.enc) + return e, name, true + } + } + + if _, params, err := mime.ParseMediaType(contentType); err == nil { + if cs, ok := params["charset"]; ok { + if e, name = Lookup(cs); e != nil { + return e, name, true + } + } + } + + if len(content) > 0 { + e, name = prescan(content) + if e != nil { + return e, name, false + } + } + + // Try to detect UTF-8. + // First eliminate any partial rune at the end. + for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- { + b := content[i] + if b < 0x80 { + break + } + if utf8.RuneStart(b) { + content = content[:i] + break + } + } + hasHighBit := false + for _, c := range content { + if c >= 0x80 { + hasHighBit = true + break + } + } + if hasHighBit && utf8.Valid(content) { + return encoding.Nop, "utf-8", false + } + + // TODO: change default depending on user's locale? + return charmap.Windows1252, "windows-1252", false +} + +// NewReader returns an io.Reader that converts the content of r to UTF-8. +// It calls DetermineEncoding to find out what r's encoding is. +func NewReader(r io.Reader, contentType string) (io.Reader, error) { + preview := make([]byte, 1024) + n, err := io.ReadFull(r, preview) + switch { + case err == io.ErrUnexpectedEOF: + preview = preview[:n] + r = bytes.NewReader(preview) + case err != nil: + return nil, err + default: + r = io.MultiReader(bytes.NewReader(preview), r) + } + + if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop { + r = transform.NewReader(r, e.NewDecoder()) + } + return r, nil +} + +// NewReaderLabel returns a reader that converts from the specified charset to +// UTF-8. It uses Lookup to find the encoding that corresponds to label, and +// returns an error if Lookup returns nil. It is suitable for use as +// encoding/xml.Decoder's CharsetReader function. +func NewReaderLabel(label string, input io.Reader) (io.Reader, error) { + e, _ := Lookup(label) + if e == nil { + return nil, fmt.Errorf("unsupported charset: %q", label) + } + return transform.NewReader(input, e.NewDecoder()), nil +} + +func prescan(content []byte) (e encoding.Encoding, name string) { + z := html.NewTokenizer(bytes.NewReader(content)) + for { + switch z.Next() { + case html.ErrorToken: + return nil, "" + + case html.StartTagToken, html.SelfClosingTagToken: + tagName, hasAttr := z.TagName() + if !bytes.Equal(tagName, []byte("meta")) { + continue + } + attrList := make(map[string]bool) + gotPragma := false + + const ( + dontKnow = iota + doNeedPragma + doNotNeedPragma + ) + needPragma := dontKnow + + name = "" + e = nil + for hasAttr { + var key, val []byte + key, val, hasAttr = z.TagAttr() + ks := string(key) + if attrList[ks] { + continue + } + attrList[ks] = true + for i, c := range val { + if 'A' <= c && c <= 'Z' { + val[i] = c + 0x20 + } + } + + switch ks { + case "http-equiv": + if bytes.Equal(val, []byte("content-type")) { + gotPragma = true + } + + case "content": + if e == nil { + name = fromMetaElement(string(val)) + if name != "" { + e, name = Lookup(name) + if e != nil { + needPragma = doNeedPragma + } + } + } + + case "charset": + e, name = Lookup(string(val)) + needPragma = doNotNeedPragma + } + } + + if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma { + continue + } + + if strings.HasPrefix(name, "utf-16") { + name = "utf-8" + e = encoding.Nop + } + + if e != nil { + return e, name + } + } + } +} + +func fromMetaElement(s string) string { + for s != "" { + csLoc := strings.Index(s, "charset") + if csLoc == -1 { + return "" + } + s = s[csLoc+len("charset"):] + s = strings.TrimLeft(s, " \t\n\f\r") + if !strings.HasPrefix(s, "=") { + continue + } + s = s[1:] + s = strings.TrimLeft(s, " \t\n\f\r") + if s == "" { + return "" + } + if q := s[0]; q == '"' || q == '\'' { + s = s[1:] + closeQuote := strings.IndexRune(s, rune(q)) + if closeQuote == -1 { + return "" + } + return s[:closeQuote] + } + + end := strings.IndexAny(s, "; \t\n\f\r") + if end == -1 { + end = len(s) + } + return s[:end] + } + return "" +} + +var boms = []struct { + bom []byte + enc string +}{ + {[]byte{0xfe, 0xff}, "utf-16be"}, + {[]byte{0xff, 0xfe}, "utf-16le"}, + {[]byte{0xef, 0xbb, 0xbf}, "utf-8"}, +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset_test.go new file mode 100644 index 00000000..e4e7d86b --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/charset_test.go @@ -0,0 +1,237 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package charset + +import ( + "bytes" + "encoding/xml" + "io/ioutil" + "runtime" + "strings" + "testing" + + "golang.org/x/text/transform" +) + +func transformString(t transform.Transformer, s string) (string, error) { + r := transform.NewReader(strings.NewReader(s), t) + b, err := ioutil.ReadAll(r) + return string(b), err +} + +type testCase struct { + utf8, other, otherEncoding string +} + +// testCases for encoding and decoding. +var testCases = []testCase{ + {"Résumé", "Résumé", "utf8"}, + {"Résumé", "R\xe9sum\xe9", "latin1"}, + {"これは漢字です。", "S0\x8c0o0\"oW[g0Y0\x020", "UTF-16LE"}, + {"これは漢字です。", "0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16BE"}, + {"Hello, world", "Hello, world", "ASCII"}, + {"Gdańsk", "Gda\xf1sk", "ISO-8859-2"}, + {"Ââ Čč Đđ Ŋŋ Õõ Šš Žž Åå Ää", "\xc2\xe2 \xc8\xe8 \xa9\xb9 \xaf\xbf \xd5\xf5 \xaa\xba \xac\xbc \xc5\xe5 \xc4\xe4", "ISO-8859-10"}, + {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"}, + {"latviešu", "latvie\xf0u", "ISO-8859-13"}, + {"Seònaid", "Se\xf2naid", "ISO-8859-14"}, + {"€1 is cheap", "\xa41 is cheap", "ISO-8859-15"}, + {"românește", "rom\xe2ne\xbate", "ISO-8859-16"}, + {"nutraĵo", "nutra\xbco", "ISO-8859-3"}, + {"Kalâdlit", "Kal\xe2dlit", "ISO-8859-4"}, + {"русский", "\xe0\xe3\xe1\xe1\xda\xd8\xd9", "ISO-8859-5"}, + {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "ISO-8859-7"}, + {"Kağan", "Ka\xf0an", "ISO-8859-9"}, + {"Résumé", "R\x8esum\x8e", "macintosh"}, + {"Gdańsk", "Gda\xf1sk", "windows-1250"}, + {"русский", "\xf0\xf3\xf1\xf1\xea\xe8\xe9", "windows-1251"}, + {"Résumé", "R\xe9sum\xe9", "windows-1252"}, + {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "windows-1253"}, + {"Kağan", "Ka\xf0an", "windows-1254"}, + {"עִבְרִית", "\xf2\xc4\xe1\xc0\xf8\xc4\xe9\xfa", "windows-1255"}, + {"العربية", "\xc7\xe1\xda\xd1\xc8\xed\xc9", "windows-1256"}, + {"latviešu", "latvie\xf0u", "windows-1257"}, + {"Việt", "Vi\xea\xf2t", "windows-1258"}, + {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "windows-874"}, + {"русский", "\xd2\xd5\xd3\xd3\xcb\xc9\xca", "KOI8-R"}, + {"українська", "\xd5\xcb\xd2\xc1\xa7\xce\xd3\xd8\xcb\xc1", "KOI8-U"}, + {"Hello 常用國字標準字體表", "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed", "big5"}, + {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"}, + {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"}, + {"עִבְרִית", "\x81\x30\xfb\x30\x81\x30\xf6\x34\x81\x30\xf9\x33\x81\x30\xf6\x30\x81\x30\xfb\x36\x81\x30\xf6\x34\x81\x30\xfa\x31\x81\x30\xfb\x38", "gb18030"}, + {"㧯", "\x82\x31\x89\x38", "gb18030"}, + {"これは漢字です。", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"}, + {"Hello, 世界!", "Hello, \x90\xa2\x8aE!", "SJIS"}, + {"イウエオカ", "\xb2\xb3\xb4\xb5\xb6", "SJIS"}, + {"これは漢字です。", "\xa4\xb3\xa4\xec\xa4\u03f4\xc1\xbb\xfa\xa4\u01e4\xb9\xa1\xa3", "EUC-JP"}, + {"Hello, 世界!", "Hello, \x1b$B@$3&\x1b(B!", "ISO-2022-JP"}, + {"다음과 같은 조건을 따라야 합니다: 저작자표시", "\xb4\xd9\xc0\xbd\xb0\xfa \xb0\xb0\xc0\xba \xc1\xb6\xb0\xc7\xc0\xbb \xb5\xfb\xb6\xf3\xbe\xdf \xc7մϴ\xd9: \xc0\xfa\xc0\xdb\xc0\xdaǥ\xbd\xc3", "EUC-KR"}, +} + +func TestDecode(t *testing.T) { + testCases := append(testCases, []testCase{ + // Replace multi-byte maximum subpart of ill-formed subsequence with + // single replacement character (WhatWG requirement). + {"Rés\ufffdumé", "Rés\xe1\x80umé", "utf8"}, + }...) + for _, tc := range testCases { + e, _ := Lookup(tc.otherEncoding) + if e == nil { + t.Errorf("%s: not found", tc.otherEncoding) + continue + } + s, err := transformString(e.NewDecoder(), tc.other) + if err != nil { + t.Errorf("%s: decode %q: %v", tc.otherEncoding, tc.other, err) + continue + } + if s != tc.utf8 { + t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.utf8) + } + } +} + +func TestEncode(t *testing.T) { + testCases := append(testCases, []testCase{ + // Use Go-style replacement. + {"Rés\xe1\x80umé", "Rés\ufffd\ufffdumé", "utf8"}, + // U+0144 LATIN SMALL LETTER N WITH ACUTE not supported by encoding. + {"Gdańsk", "Gdańsk", "ISO-8859-11"}, + {"\ufffd", "�", "ISO-8859-11"}, + {"a\xe1\x80b", "a��b", "ISO-8859-11"}, + }...) + for _, tc := range testCases { + e, _ := Lookup(tc.otherEncoding) + if e == nil { + t.Errorf("%s: not found", tc.otherEncoding) + continue + } + s, err := transformString(e.NewEncoder(), tc.utf8) + if err != nil { + t.Errorf("%s: encode %q: %s", tc.otherEncoding, tc.utf8, err) + continue + } + if s != tc.other { + t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.other) + } + } +} + +var sniffTestCases = []struct { + filename, declared, want string +}{ + {"HTTP-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"UTF-16LE-BOM.html", "", "utf-16le"}, + {"UTF-16BE-BOM.html", "", "utf-16be"}, + {"meta-content-attribute.html", "text/html", "iso-8859-15"}, + {"meta-charset-attribute.html", "text/html", "iso-8859-15"}, + {"No-encoding-declaration.html", "text/html", "utf-8"}, + {"HTTP-vs-UTF-8-BOM.html", "text/html; charset=iso-8859-15", "utf-8"}, + {"HTTP-vs-meta-content.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"HTTP-vs-meta-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"UTF-8-BOM-vs-meta-content.html", "text/html", "utf-8"}, + {"UTF-8-BOM-vs-meta-charset.html", "text/html", "utf-8"}, +} + +func TestSniff(t *testing.T) { + switch runtime.GOOS { + case "nacl": // platforms that don't permit direct file system access + t.Skipf("not supported on %q", runtime.GOOS) + } + + for _, tc := range sniffTestCases { + content, err := ioutil.ReadFile("testdata/" + tc.filename) + if err != nil { + t.Errorf("%s: error reading file: %v", tc.filename, err) + continue + } + + _, name, _ := DetermineEncoding(content, tc.declared) + if name != tc.want { + t.Errorf("%s: got %q, want %q", tc.filename, name, tc.want) + continue + } + } +} + +func TestReader(t *testing.T) { + switch runtime.GOOS { + case "nacl": // platforms that don't permit direct file system access + t.Skipf("not supported on %q", runtime.GOOS) + } + + for _, tc := range sniffTestCases { + content, err := ioutil.ReadFile("testdata/" + tc.filename) + if err != nil { + t.Errorf("%s: error reading file: %v", tc.filename, err) + continue + } + + r, err := NewReader(bytes.NewReader(content), tc.declared) + if err != nil { + t.Errorf("%s: error creating reader: %v", tc.filename, err) + continue + } + + got, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("%s: error reading from charset.NewReader: %v", tc.filename, err) + continue + } + + e, _ := Lookup(tc.want) + want, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(content), e.NewDecoder())) + if err != nil { + t.Errorf("%s: error decoding with hard-coded charset name: %v", tc.filename, err) + continue + } + + if !bytes.Equal(got, want) { + t.Errorf("%s: got %q, want %q", tc.filename, got, want) + continue + } + } +} + +var metaTestCases = []struct { + meta, want string +}{ + {"", ""}, + {"text/html", ""}, + {"text/html; charset utf-8", ""}, + {"text/html; charset=latin-2", "latin-2"}, + {"text/html; charset; charset = utf-8", "utf-8"}, + {`charset="big5"`, "big5"}, + {"charset='shift_jis'", "shift_jis"}, +} + +func TestFromMeta(t *testing.T) { + for _, tc := range metaTestCases { + got := fromMetaElement(tc.meta) + if got != tc.want { + t.Errorf("%q: got %q, want %q", tc.meta, got, tc.want) + } + } +} + +func TestXML(t *testing.T) { + const s = "r\xe9sum\xe9" + + d := xml.NewDecoder(strings.NewReader(s)) + d.CharsetReader = NewReaderLabel + + var a struct { + Word string + } + err := d.Decode(&a) + if err != nil { + t.Fatalf("Decode: %v", err) + } + + want := "résumé" + if a.Word != want { + t.Errorf("got %q, want %q", a.Word, want) + } +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html new file mode 100644 index 00000000..9915fa0e --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html @@ -0,0 +1,48 @@ + + + + HTTP charset + + + + + + + + + + + +

    HTTP charset

    + + +
    + + +
     
    + + + + + +
    +

    The character encoding of a page can be set using the HTTP header charset declaration.

    +

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

    The only character encoding declaration for this HTML file is in the HTTP header, which sets the encoding to ISO 8859-15.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-001
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html new file mode 100644 index 00000000..26e5d8b4 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html @@ -0,0 +1,48 @@ + + + + HTTP vs UTF-8 BOM + + + + + + + + + + + +

    HTTP vs UTF-8 BOM

    + + +
    + + +
     
    + + + + + +
    +

    A character encoding set in the HTTP header has lower precedence than the UTF-8 signature.

    +

    The HTTP header attempts to set the character encoding to ISO 8859-15. The page starts with a UTF-8 signature.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

    If the test is unsuccessful, the characters  should appear at the top of the page. These represent the bytes that make up the UTF-8 signature when encountered in the ISO 8859-15 encoding.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-034
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html new file mode 100644 index 00000000..2f07e951 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html @@ -0,0 +1,49 @@ + + + + HTTP vs meta charset + + + + + + + + + + + +

    HTTP vs meta charset

    + + +
    + + +
     
    + + + + + +
    +

    The HTTP header has a higher precedence than an encoding declaration in a meta charset attribute.

    +

    The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-1.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-018
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html new file mode 100644 index 00000000..6853cdde --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html @@ -0,0 +1,49 @@ + + + + HTTP vs meta content + + + + + + + + + + + +

    HTTP vs meta content

    + + +
    + + +
     
    + + + + + +
    +

    The HTTP header has a higher precedence than an encoding declaration in a meta content attribute.

    +

    The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-1.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-016
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html new file mode 100644 index 00000000..612e26c6 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html @@ -0,0 +1,47 @@ + + + + No encoding declaration + + + + + + + + + + + +

    No encoding declaration

    + + +
    + + +
     
    + + + + + +
    +

    A page with no encoding information in HTTP, BOM, XML declaration or meta element will be treated as UTF-8.

    +

    The test on this page contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-015
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/README b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/README new file mode 100644 index 00000000..38ef0f9f --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/README @@ -0,0 +1,9 @@ +These test cases come from +http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics + +Distributed under both the W3C Test Suite License +(http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) +and the W3C 3-clause BSD License +(http://www.w3.org/Consortium/Legal/2008/03-bsd-license). +To contribute to a W3C Test Suite, see the policies and contribution +forms (http://www.w3.org/2004/10/27-testcases). diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html new file mode 100644 index 0000000000000000000000000000000000000000..3abf7a9343c20518e57dfea58b374fb0f4fb58a1 GIT binary patch literal 2670 zcmcJR?QRoS5Qc}JAoU&=BQ-(7b^;2j8i*i3RV1JlO@;VXIsPurV!WHiDdLW}i`*CO z^UnC>tih=KsVr;H&Y7?C&O3AV(?534uG?e##U9y_y|!QNi4``n+D>d{2lky^LnFNx z?9HrarH$>rwQR_$g)Hk0*&STI*EYq|47~&U9sfUB+ji})9eR{QqCUra7oDsZ5obtB zdxP%<)-$4Q;rSHJiM>U(#ZI=;?n^BC?Dp6lu=~_1-lnX3u03&2BlmQIY>L+!Uq7XoytKw^Q#oZSM?3*J?)&ojG&yzQRkC!Ml5JE?ax;lp_NYEcdUht`ZswOviB~L5hmJ|pXI71nn20w;>vG! zQGB$EE9&wC``&J#_Ym~PgRu-Bd>1!pOp0||k`kr=VJ zfH6I6rmRaeHA7U-A^OTsT+|d2a^i(>DePzZ{)ibXoCBvJnuYrd-3kkN$uy{qQK;=*Y;S87ro12aTgu^i*%f8zC3>a}9DIe4cfxOzsCw&(cqvP9{ud{N6f` z#TNDY(B6@Gpr|uN+%&x^XZjBHdc@2vsM(Tyc2=vshHQ5w+obmp>tuWT(t4BTUGAQw zxeI$UGSLUBg=WFbF;4f@4=^P2AgY@CFn8A`bcC=_&~)fiDe)#cUARRBzJ^k|%X)69 z+{Cb`wq}Rsg%B62CC_tK!AV(W{(MV?#mndR46CU#BUN<{8e?*oT+!pE5wF#O#TR#a z$9qRT)tpbw8zAI~QQJg2C3|6$I%(T(;`zOMy6SO+&;pG=c#2P|P-WZn$$DpWJlC3U z3*nvmz zwP{u~r$L?-m3uqp9I1+#3yE|3M$(s-BEtih=LQ>`qYoiktOop(wi%!;yh%+Rm z{e|xntY<{q!1F1Z6MKtngPm-p-4|H&+3m4AVE3_AyiHm6Tzlf4M(*ht*%YrezJ6kr zHGj45pc?64*$Cm%-zseWMA`x;)v*~jA=i}szqts9xmQkS`M11|(H7bTXAycsXU53+ zJ?120SRZeyiFjW7enPN`bxk$IaWV3o48oJF7D&2ysoY;6(s6%6vVfaYd&mC=erK!) zNGI^7upQgN)53OHe_VE<@J+G8*Y|p*)zB2Thdi}+YR<5QWHm!|a_*AoZXuv7)$xe| zm3Q$D7{|#}{m4X&UY!6(ZhyYi2(5JLzGE$H)W6BQklnjPMwn<Yvv7Z*TVWwD*=E3QpH37* z#lqXJA0A~J9T_<^W5smspmDg2p6ac5Bjn+~LAoow%1TCdZ*$K8`O zw_$HaCi+0N&@7la#_7KL5r$+QL{)Pi=I&aDjt~|Knht#`CEi4*3%97i_fSfASlwUz0=3V0GCxY}z81UC-nP=CGt2OqYV$ zoRCo+qM9YX*3FFORLC=E3B~S@+KROyk4r5 yX7?DaslDfIebqXgC!KKp4IYy+W~X?ddE6o=`A+x#x0AK&6MF#W&AXxbRrv+SX}PNa literal 0 HcmV?d00001 diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html new file mode 100644 index 00000000..83de4333 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html @@ -0,0 +1,49 @@ + + + + UTF-8 BOM vs meta charset + + + + + + + + + + + +

    UTF-8 BOM vs meta charset

    + + +
    + + +
     
    + + + + + +
    +

    A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta charset attribute declares a different encoding.

    +

    The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-038
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html new file mode 100644 index 00000000..501aac2d --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html @@ -0,0 +1,48 @@ + + + + UTF-8 BOM vs meta content + + + + + + + + + + + +

    UTF-8 BOM vs meta content

    + + +
    + + +
     
    + + + + + +
    +

    A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta content attribute declares a different encoding.

    +

    The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-037
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html new file mode 100644 index 00000000..2d7d25ab --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html @@ -0,0 +1,48 @@ + + + + meta charset attribute + + + + + + + + + + + +

    meta charset attribute

    + + +
    + + +
     
    + + + + + +
    +

    The character encoding of the page can be set by a meta element with charset attribute.

    +

    The only character encoding declaration for this HTML file is in the charset attribute of the meta element, which declares the encoding to be ISO 8859-15.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-009
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-content-attribute.html b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-content-attribute.html new file mode 100644 index 00000000..1c3f228e --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/charset/testdata/meta-content-attribute.html @@ -0,0 +1,48 @@ + + + + meta content attribute + + + + + + + + + + + +

    meta content attribute

    + + +
    + + +
     
    + + + + + +
    +

    The character encoding of the page can be set by a meta element with http-equiv and content attributes.

    +

    The only character encoding declaration for this HTML file is in the content attribute of the meta element, which declares the encoding to be ISO 8859-15.

    The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

    +
    +
    +
    HTML5
    +

    the-input-byte-stream-007
    Result summary & related tests
    Detailed results for this test
    Link to spec

    +
    Assumptions:
    • The default encoding for the browser you are testing is not set to ISO 8859-15.
    • +
    • The test is read from a server that supports HTTP.
    +
    + + + + + + diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/const.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/const.go new file mode 100644 index 00000000..52f651ff --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/const.go @@ -0,0 +1,102 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// Section 12.2.3.2 of the HTML5 specification says "The following elements +// have varying levels of special parsing rules". +// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements +var isSpecialElementMap = map[string]bool{ + "address": true, + "applet": true, + "area": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "bgsound": true, + "blockquote": true, + "body": true, + "br": true, + "button": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "dd": true, + "details": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "embed": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hgroup": true, + "hr": true, + "html": true, + "iframe": true, + "img": true, + "input": true, + "isindex": true, + "li": true, + "link": true, + "listing": true, + "marquee": true, + "menu": true, + "meta": true, + "nav": true, + "noembed": true, + "noframes": true, + "noscript": true, + "object": true, + "ol": true, + "p": true, + "param": true, + "plaintext": true, + "pre": true, + "script": true, + "section": true, + "select": true, + "source": true, + "style": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "template": true, + "textarea": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "track": true, + "ul": true, + "wbr": true, + "xmp": true, +} + +func isSpecialElement(element *Node) bool { + switch element.Namespace { + case "", "html": + return isSpecialElementMap[element.Data] + case "svg": + return element.Data == "foreignObject" + } + return false +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doc.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doc.go new file mode 100644 index 00000000..94f49687 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doc.go @@ -0,0 +1,106 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package html implements an HTML5-compliant tokenizer and parser. + +Tokenization is done by creating a Tokenizer for an io.Reader r. It is the +caller's responsibility to ensure that r provides UTF-8 encoded HTML. + + z := html.NewTokenizer(r) + +Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), +which parses the next token and returns its type, or an error: + + for { + tt := z.Next() + if tt == html.ErrorToken { + // ... + return ... + } + // Process the current token. + } + +There are two APIs for retrieving the current token. The high-level API is to +call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs +allow optionally calling Raw after Next but before Token, Text, TagName, or +TagAttr. In EBNF notation, the valid call sequence per token is: + + Next {Raw} [ Token | Text | TagName {TagAttr} ] + +Token returns an independent data structure that completely describes a token. +Entities (such as "<") are unescaped, tag names and attribute keys are +lower-cased, and attributes are collected into a []Attribute. For example: + + for { + if z.Next() == html.ErrorToken { + // Returning io.EOF indicates success. + return z.Err() + } + emitToken(z.Token()) + } + +The low-level API performs fewer allocations and copies, but the contents of +the []byte values returned by Text, TagName and TagAttr may change on the next +call to Next. For example, to extract an HTML page's anchor text: + + depth := 0 + for { + tt := z.Next() + switch tt { + case ErrorToken: + return z.Err() + case TextToken: + if depth > 0 { + // emitBytes should copy the []byte it receives, + // if it doesn't process it immediately. + emitBytes(z.Text()) + } + case StartTagToken, EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + +Parsing is done by calling Parse with an io.Reader, which returns the root of +the parse tree (the document element) as a *Node. It is the caller's +responsibility to ensure that the Reader provides UTF-8 encoded HTML. For +example, to process each anchor node in depth-first order: + + doc, err := html.Parse(r) + if err != nil { + // ... + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + // Do something with n... + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + +The relevant specifications include: +https://html.spec.whatwg.org/multipage/syntax.html and +https://html.spec.whatwg.org/multipage/syntax.html#tokenization +*/ +package html // import "golang.org/x/net/html" + +// The tokenization algorithm implemented by this package is not a line-by-line +// transliteration of the relatively verbose state-machine in the WHATWG +// specification. A more direct approach is used instead, where the program +// counter implies the state, such as whether it is tokenizing a tag or a text +// node. Specification compliance is verified by checking expected and actual +// outputs over a test suite rather than aiming for algorithmic fidelity. + +// TODO(nigeltao): Does a DOM API belong in this package or a separate one? +// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doctype.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doctype.go new file mode 100644 index 00000000..c484e5a9 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/doctype.go @@ -0,0 +1,156 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "strings" +) + +// parseDoctype parses the data from a DoctypeToken into a name, +// public identifier, and system identifier. It returns a Node whose Type +// is DoctypeNode, whose Data is the name, and which has attributes +// named "system" and "public" for the two identifiers if they were present. +// quirks is whether the document should be parsed in "quirks mode". +func parseDoctype(s string) (n *Node, quirks bool) { + n = &Node{Type: DoctypeNode} + + // Find the name. + space := strings.IndexAny(s, whitespace) + if space == -1 { + space = len(s) + } + n.Data = s[:space] + // The comparison to "html" is case-sensitive. + if n.Data != "html" { + quirks = true + } + n.Data = strings.ToLower(n.Data) + s = strings.TrimLeft(s[space:], whitespace) + + if len(s) < 6 { + // It can't start with "PUBLIC" or "SYSTEM". + // Ignore the rest of the string. + return n, quirks || s != "" + } + + key := strings.ToLower(s[:6]) + s = s[6:] + for key == "public" || key == "system" { + s = strings.TrimLeft(s, whitespace) + if s == "" { + break + } + quote := s[0] + if quote != '"' && quote != '\'' { + break + } + s = s[1:] + q := strings.IndexRune(s, rune(quote)) + var id string + if q == -1 { + id = s + s = "" + } else { + id = s[:q] + s = s[q+1:] + } + n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) + if key == "public" { + key = "system" + } else { + key = "" + } + } + + if key != "" || s != "" { + quirks = true + } else if len(n.Attr) > 0 { + if n.Attr[0].Key == "public" { + public := strings.ToLower(n.Attr[0].Val) + switch public { + case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": + quirks = true + default: + for _, q := range quirkyIDs { + if strings.HasPrefix(public, q) { + quirks = true + break + } + } + } + // The following two public IDs only cause quirks mode if there is no system ID. + if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || + strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { + quirks = true + } + } + if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && + strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + quirks = true + } + } + + return n, quirks +} + +// quirkyIDs is a list of public doctype identifiers that cause a document +// to be interpreted in quirks mode. The identifiers should be in lower case. +var quirkyIDs = []string{ + "+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//", +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity.go new file mode 100644 index 00000000..a50c04c6 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity.go @@ -0,0 +1,2253 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// All entities that do not end with ';' are 6 or fewer bytes long. +const longestEntityWithoutSemicolon = 6 + +// entity is a map from HTML entity names to their values. The semicolon matters: +// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig;": '\U000000C6', + "AMP;": '\U00000026', + "Aacute;": '\U000000C1', + "Abreve;": '\U00000102', + "Acirc;": '\U000000C2', + "Acy;": '\U00000410', + "Afr;": '\U0001D504', + "Agrave;": '\U000000C0', + "Alpha;": '\U00000391', + "Amacr;": '\U00000100', + "And;": '\U00002A53', + "Aogon;": '\U00000104', + "Aopf;": '\U0001D538', + "ApplyFunction;": '\U00002061', + "Aring;": '\U000000C5', + "Ascr;": '\U0001D49C', + "Assign;": '\U00002254', + "Atilde;": '\U000000C3', + "Auml;": '\U000000C4', + "Backslash;": '\U00002216', + "Barv;": '\U00002AE7', + "Barwed;": '\U00002306', + "Bcy;": '\U00000411', + "Because;": '\U00002235', + "Bernoullis;": '\U0000212C', + "Beta;": '\U00000392', + "Bfr;": '\U0001D505', + "Bopf;": '\U0001D539', + "Breve;": '\U000002D8', + "Bscr;": '\U0000212C', + "Bumpeq;": '\U0000224E', + "CHcy;": '\U00000427', + "COPY;": '\U000000A9', + "Cacute;": '\U00000106', + "Cap;": '\U000022D2', + "CapitalDifferentialD;": '\U00002145', + "Cayleys;": '\U0000212D', + "Ccaron;": '\U0000010C', + "Ccedil;": '\U000000C7', + "Ccirc;": '\U00000108', + "Cconint;": '\U00002230', + "Cdot;": '\U0000010A', + "Cedilla;": '\U000000B8', + "CenterDot;": '\U000000B7', + "Cfr;": '\U0000212D', + "Chi;": '\U000003A7', + "CircleDot;": '\U00002299', + "CircleMinus;": '\U00002296', + "CirclePlus;": '\U00002295', + "CircleTimes;": '\U00002297', + "ClockwiseContourIntegral;": '\U00002232', + "CloseCurlyDoubleQuote;": '\U0000201D', + "CloseCurlyQuote;": '\U00002019', + "Colon;": '\U00002237', + "Colone;": '\U00002A74', + "Congruent;": '\U00002261', + "Conint;": '\U0000222F', + "ContourIntegral;": '\U0000222E', + "Copf;": '\U00002102', + "Coproduct;": '\U00002210', + "CounterClockwiseContourIntegral;": '\U00002233', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', +} + +// HTML entities that are two unicode codepoints. +var entity2 = map[string][2]rune{ + // TODO(nigeltao): Handle replacements that are wider than their names. + // "nLt;": {'\u226A', '\u20D2'}, + // "nGt;": {'\u226B', '\u20D2'}, + "NotEqualTilde;": {'\u2242', '\u0338'}, + "NotGreaterFullEqual;": {'\u2267', '\u0338'}, + "NotGreaterGreater;": {'\u226B', '\u0338'}, + "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, + "NotHumpDownHump;": {'\u224E', '\u0338'}, + "NotHumpEqual;": {'\u224F', '\u0338'}, + "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, + "NotLessLess;": {'\u226A', '\u0338'}, + "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, + "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, + "NotNestedLessLess;": {'\u2AA1', '\u0338'}, + "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, + "NotRightTriangleBar;": {'\u29D0', '\u0338'}, + "NotSquareSubset;": {'\u228F', '\u0338'}, + "NotSquareSuperset;": {'\u2290', '\u0338'}, + "NotSubset;": {'\u2282', '\u20D2'}, + "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, + "NotSucceedsTilde;": {'\u227F', '\u0338'}, + "NotSuperset;": {'\u2283', '\u20D2'}, + "ThickSpace;": {'\u205F', '\u200A'}, + "acE;": {'\u223E', '\u0333'}, + "bne;": {'\u003D', '\u20E5'}, + "bnequiv;": {'\u2261', '\u20E5'}, + "caps;": {'\u2229', '\uFE00'}, + "cups;": {'\u222A', '\uFE00'}, + "fjlig;": {'\u0066', '\u006A'}, + "gesl;": {'\u22DB', '\uFE00'}, + "gvertneqq;": {'\u2269', '\uFE00'}, + "gvnE;": {'\u2269', '\uFE00'}, + "lates;": {'\u2AAD', '\uFE00'}, + "lesg;": {'\u22DA', '\uFE00'}, + "lvertneqq;": {'\u2268', '\uFE00'}, + "lvnE;": {'\u2268', '\uFE00'}, + "nGg;": {'\u22D9', '\u0338'}, + "nGtv;": {'\u226B', '\u0338'}, + "nLl;": {'\u22D8', '\u0338'}, + "nLtv;": {'\u226A', '\u0338'}, + "nang;": {'\u2220', '\u20D2'}, + "napE;": {'\u2A70', '\u0338'}, + "napid;": {'\u224B', '\u0338'}, + "nbump;": {'\u224E', '\u0338'}, + "nbumpe;": {'\u224F', '\u0338'}, + "ncongdot;": {'\u2A6D', '\u0338'}, + "nedot;": {'\u2250', '\u0338'}, + "nesim;": {'\u2242', '\u0338'}, + "ngE;": {'\u2267', '\u0338'}, + "ngeqq;": {'\u2267', '\u0338'}, + "ngeqslant;": {'\u2A7E', '\u0338'}, + "nges;": {'\u2A7E', '\u0338'}, + "nlE;": {'\u2266', '\u0338'}, + "nleqq;": {'\u2266', '\u0338'}, + "nleqslant;": {'\u2A7D', '\u0338'}, + "nles;": {'\u2A7D', '\u0338'}, + "notinE;": {'\u22F9', '\u0338'}, + "notindot;": {'\u22F5', '\u0338'}, + "nparsl;": {'\u2AFD', '\u20E5'}, + "npart;": {'\u2202', '\u0338'}, + "npre;": {'\u2AAF', '\u0338'}, + "npreceq;": {'\u2AAF', '\u0338'}, + "nrarrc;": {'\u2933', '\u0338'}, + "nrarrw;": {'\u219D', '\u0338'}, + "nsce;": {'\u2AB0', '\u0338'}, + "nsubE;": {'\u2AC5', '\u0338'}, + "nsubset;": {'\u2282', '\u20D2'}, + "nsubseteqq;": {'\u2AC5', '\u0338'}, + "nsucceq;": {'\u2AB0', '\u0338'}, + "nsupE;": {'\u2AC6', '\u0338'}, + "nsupset;": {'\u2283', '\u20D2'}, + "nsupseteqq;": {'\u2AC6', '\u0338'}, + "nvap;": {'\u224D', '\u20D2'}, + "nvge;": {'\u2265', '\u20D2'}, + "nvgt;": {'\u003E', '\u20D2'}, + "nvle;": {'\u2264', '\u20D2'}, + "nvlt;": {'\u003C', '\u20D2'}, + "nvltrie;": {'\u22B4', '\u20D2'}, + "nvrtrie;": {'\u22B5', '\u20D2'}, + "nvsim;": {'\u223C', '\u20D2'}, + "race;": {'\u223D', '\u0331'}, + "smtes;": {'\u2AAC', '\uFE00'}, + "sqcaps;": {'\u2293', '\uFE00'}, + "sqcups;": {'\u2294', '\uFE00'}, + "varsubsetneq;": {'\u228A', '\uFE00'}, + "varsubsetneqq;": {'\u2ACB', '\uFE00'}, + "varsupsetneq;": {'\u228B', '\uFE00'}, + "varsupsetneqq;": {'\u2ACC', '\uFE00'}, + "vnsub;": {'\u2282', '\u20D2'}, + "vnsup;": {'\u2283', '\u20D2'}, + "vsubnE;": {'\u2ACB', '\uFE00'}, + "vsubne;": {'\u228A', '\uFE00'}, + "vsupnE;": {'\u2ACC', '\uFE00'}, + "vsupne;": {'\u228B', '\uFE00'}, +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity_test.go new file mode 100644 index 00000000..b53f866f --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/entity_test.go @@ -0,0 +1,29 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "testing" + "unicode/utf8" +) + +func TestEntityLength(t *testing.T) { + // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). + // The +1 comes from the leading "&". This property implies that the length of + // unescaped text is <= the length of escaped text. + for k, v := range entity { + if 1+len(k) < utf8.RuneLen(v) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) + } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } + } + for k, v := range entity2 { + if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) + } + } +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape.go new file mode 100644 index 00000000..d8561396 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape.go @@ -0,0 +1,258 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "bytes" + "strings" + "unicode/utf8" +) + +// These replacements permit compatibility with old numeric entities that +// assumed Windows-1252 encoding. +// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference +var replacementTable = [...]rune{ + '\u20AC', // First entry is what 0x80 should be replaced with. + '\u0081', + '\u201A', + '\u0192', + '\u201E', + '\u2026', + '\u2020', + '\u2021', + '\u02C6', + '\u2030', + '\u0160', + '\u2039', + '\u0152', + '\u008D', + '\u017D', + '\u008F', + '\u0090', + '\u2018', + '\u2019', + '\u201C', + '\u201D', + '\u2022', + '\u2013', + '\u2014', + '\u02DC', + '\u2122', + '\u0161', + '\u203A', + '\u0153', + '\u009D', + '\u017E', + '\u0178', // Last entry is 0x9F. + // 0x00->'\uFFFD' is handled programmatically. + // 0x0D->'\u000D' is a no-op. +} + +// unescapeEntity reads an entity like "<" from b[src:] and writes the +// corresponding "<" to b[dst:], returning the incremented dst and src cursors. +// Precondition: b[src] == '&' && dst <= src. +// attribute should be true if parsing an attribute value. +func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { + // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference + + // i starts at 1 because we already know that s[0] == '&'. + i, s := 1, b[src:] + + if len(s) <= 1 { + b[dst] = b[src] + return dst + 1, src + 1 + } + + if s[i] == '#' { + if len(s) <= 3 { // We need to have at least "&#.". + b[dst] = b[src] + return dst + 1, src + 1 + } + i++ + c := s[i] + hex := false + if c == 'x' || c == 'X' { + hex = true + i++ + } + + x := '\x00' + for i < len(s) { + c = s[i] + i++ + if hex { + if '0' <= c && c <= '9' { + x = 16*x + rune(c) - '0' + continue + } else if 'a' <= c && c <= 'f' { + x = 16*x + rune(c) - 'a' + 10 + continue + } else if 'A' <= c && c <= 'F' { + x = 16*x + rune(c) - 'A' + 10 + continue + } + } else if '0' <= c && c <= '9' { + x = 10*x + rune(c) - '0' + continue + } + if c != ';' { + i-- + } + break + } + + if i <= 3 { // No characters matched. + b[dst] = b[src] + return dst + 1, src + 1 + } + + if 0x80 <= x && x <= 0x9F { + // Replace characters from Windows-1252 with UTF-8 equivalents. + x = replacementTable[x-0x80] + } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { + // Replace invalid characters with the replacement character. + x = '\uFFFD' + } + + return dst + utf8.EncodeRune(b[dst:], x), src + i + } + + // Consume the maximum number of characters possible, with the + // consumed characters matching one of the named references. + + for i < len(s) { + c := s[i] + i++ + // Lower-cased characters are more common in entities, so we check for them first. + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + continue + } + if c != ';' { + i-- + } + break + } + + entityName := string(s[1:i]) + if entityName == "" { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[entityName]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + i + } else if x := entity2[entityName]; x[0] != 0 { + dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) + return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[entityName[:j]]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } + } + + dst1, src1 = dst+i, src+i + copy(b[dst:dst1], b[src:src1]) + return dst1, src1 +} + +// unescape unescapes b's entities in-place, so that "a<b" becomes "a': + esc = ">" + case '"': + // """ is shorter than """. + esc = """ + case '\r': + esc = " " + default: + panic("unrecognized escape character") + } + s = s[i+1:] + if _, err := w.WriteString(esc); err != nil { + return err + } + i = strings.IndexAny(s, escapedChars) + } + _, err := w.WriteString(s) + return err +} + +// EscapeString escapes special characters like "<" to become "<". It +// escapes only five such characters: <, >, &, ' and ". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func EscapeString(s string) string { + if strings.IndexAny(s, escapedChars) == -1 { + return s + } + var buf bytes.Buffer + escape(&buf, s) + return buf.String() +} + +// UnescapeString unescapes entities like "<" to become "<". It unescapes a +// larger range of entities than EscapeString escapes. For example, "á" +// unescapes to "á", as does "á" and "&xE1;". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func UnescapeString(s string) string { + for _, c := range s { + if c == '&' { + return string(unescape([]byte(s), false)) + } + } + return s +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape_test.go new file mode 100644 index 00000000..b405d4b4 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/escape_test.go @@ -0,0 +1,97 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import "testing" + +type unescapeTest struct { + // A short description of the test case. + desc string + // The HTML text. + html string + // The unescaped text. + unescaped string +} + +var unescapeTests = []unescapeTest{ + // Handle no entities. + { + "copy", + "A\ttext\nstring", + "A\ttext\nstring", + }, + // Handle simple named entities. + { + "simple", + "& > <", + "& > <", + }, + // Handle hitting the end of the string. + { + "stringEnd", + "& &", + "& &", + }, + // Handle entities with two codepoints. + { + "multiCodepoint", + "text ⋛︀ blah", + "text \u22db\ufe00 blah", + }, + // Handle decimal numeric entities. + { + "decimalEntity", + "Delta = Δ ", + "Delta = Δ ", + }, + // Handle hexadecimal numeric entities. + { + "hexadecimalEntity", + "Lambda = λ = λ ", + "Lambda = λ = λ ", + }, + // Handle numeric early termination. + { + "numericEnds", + "&# &#x €43 © = ©f = ©", + "&# &#x €43 © = ©f = ©", + }, + // Handle numeric ISO-8859-1 entity replacements. + { + "numericReplacements", + "Footnote‡", + "Footnote‡", + }, +} + +func TestUnescape(t *testing.T) { + for _, tt := range unescapeTests { + unescaped := UnescapeString(tt.html) + if unescaped != tt.unescaped { + t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) + } + } +} + +func TestUnescapeEscape(t *testing.T) { + ss := []string{ + ``, + `abc def`, + `a & b`, + `a&b`, + `a & b`, + `"`, + `"`, + `"<&>"`, + `"<&>"`, + `3&5==1 && 0<1, "0<1", a+acute=á`, + `The special characters are: <, >, &, ' and "`, + } + for _, s := range ss { + if got := UnescapeString(EscapeString(s)); got != s { + t.Errorf("got %q want %q", got, s) + } + } +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/example_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/example_test.go new file mode 100644 index 00000000..0b06ed77 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/example_test.go @@ -0,0 +1,40 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This example demonstrates parsing HTML data and walking the resulting tree. +package html_test + +import ( + "fmt" + "log" + "strings" + + "golang.org/x/net/html" +) + +func ExampleParse() { + s := `

    Links:

    ` + doc, err := html.Parse(strings.NewReader(s)) + if err != nil { + log.Fatal(err) + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + for _, a := range n.Attr { + if a.Key == "href" { + fmt.Println(a.Val) + break + } + } + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + // Output: + // foo + // /bar/baz +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/foreign.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/foreign.go new file mode 100644 index 00000000..d3b38440 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/foreign.go @@ -0,0 +1,226 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "strings" +) + +func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { + for i := range aa { + if newName, ok := nameMap[aa[i].Key]; ok { + aa[i].Key = newName + } + } +} + +func adjustForeignAttributes(aa []Attribute) { + for i, a := range aa { + if a.Key == "" || a.Key[0] != 'x' { + continue + } + switch a.Key { + case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", + "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + j := strings.Index(a.Key, ":") + aa[i].Namespace = a.Key[:j] + aa[i].Key = a.Key[j+1:] + } + } +} + +func htmlIntegrationPoint(n *Node) bool { + if n.Type != ElementNode { + return false + } + switch n.Namespace { + case "math": + if n.Data == "annotation-xml" { + for _, a := range n.Attr { + if a.Key == "encoding" { + val := strings.ToLower(a.Val) + if val == "text/html" || val == "application/xhtml+xml" { + return true + } + } + } + } + case "svg": + switch n.Data { + case "desc", "foreignObject", "title": + return true + } + } + return false +} + +func mathMLTextIntegrationPoint(n *Node) bool { + if n.Namespace != "math" { + return false + } + switch n.Data { + case "mi", "mo", "mn", "ms", "mtext": + return true + } + return false +} + +// Section 12.2.5.5. +var breakout = map[string]bool{ + "b": true, + "big": true, + "blockquote": true, + "body": true, + "br": true, + "center": true, + "code": true, + "dd": true, + "div": true, + "dl": true, + "dt": true, + "em": true, + "embed": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "hr": true, + "i": true, + "img": true, + "li": true, + "listing": true, + "menu": true, + "meta": true, + "nobr": true, + "ol": true, + "p": true, + "pre": true, + "ruby": true, + "s": true, + "small": true, + "span": true, + "strong": true, + "strike": true, + "sub": true, + "sup": true, + "table": true, + "tt": true, + "u": true, + "ul": true, + "var": true, +} + +// Section 12.2.5.5. +var svgTagNameAdjustments = map[string]string{ + "altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath", +} + +// Section 12.2.5.1 +var mathMLAttributeAdjustments = map[string]string{ + "definitionurl": "definitionURL", +} + +var svgAttributeAdjustments = map[string]string{ + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "contentscripttype": "contentScriptType", + "contentstyletype": "contentStyleType", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "externalresourcesrequired": "externalResourcesRequired", + "filterres": "filterRes", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node.go new file mode 100644 index 00000000..26b657ae --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node.go @@ -0,0 +1,193 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "golang.org/x/net/html/atom" +) + +// A NodeType is the type of a Node. +type NodeType uint32 + +const ( + ErrorNode NodeType = iota + TextNode + DocumentNode + ElementNode + CommentNode + DoctypeNode + scopeMarkerNode +) + +// Section 12.2.3.3 says "scope markers are inserted when entering applet +// elements, buttons, object elements, marquees, table cells, and table +// captions, and are used to prevent formatting from 'leaking'". +var scopeMarker = Node{Type: scopeMarkerNode} + +// A Node consists of a NodeType and some Data (tag name for element nodes, +// content for text) and are part of a tree of Nodes. Element nodes may also +// have a Namespace and contain a slice of Attributes. Data is unescaped, so +// that it looks like "a 0 { + return (*s)[i-1] + } + return nil +} + +// index returns the index of the top-most occurrence of n in the stack, or -1 +// if n is not present. +func (s *nodeStack) index(n *Node) int { + for i := len(*s) - 1; i >= 0; i-- { + if (*s)[i] == n { + return i + } + } + return -1 +} + +// insert inserts a node at the given index. +func (s *nodeStack) insert(i int, n *Node) { + (*s) = append(*s, nil) + copy((*s)[i+1:], (*s)[i:]) + (*s)[i] = n +} + +// remove removes a node from the stack. It is a no-op if n is not present. +func (s *nodeStack) remove(n *Node) { + i := s.index(n) + if i == -1 { + return + } + copy((*s)[i:], (*s)[i+1:]) + j := len(*s) - 1 + (*s)[j] = nil + *s = (*s)[:j] +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node_test.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node_test.go new file mode 100644 index 00000000..471102f3 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/node_test.go @@ -0,0 +1,146 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "fmt" +) + +// checkTreeConsistency checks that a node and its descendants are all +// consistent in their parent/child/sibling relationships. +func checkTreeConsistency(n *Node) error { + return checkTreeConsistency1(n, 0) +} + +func checkTreeConsistency1(n *Node, depth int) error { + if depth == 1e4 { + return fmt.Errorf("html: tree looks like it contains a cycle") + } + if err := checkNodeConsistency(n); err != nil { + return err + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + if err := checkTreeConsistency1(c, depth+1); err != nil { + return err + } + } + return nil +} + +// checkNodeConsistency checks that a node's parent/child/sibling relationships +// are consistent. +func checkNodeConsistency(n *Node) error { + if n == nil { + return nil + } + + nParent := 0 + for p := n.Parent; p != nil; p = p.Parent { + nParent++ + if nParent == 1e4 { + return fmt.Errorf("html: parent list looks like an infinite loop") + } + } + + nForward := 0 + for c := n.FirstChild; c != nil; c = c.NextSibling { + nForward++ + if nForward == 1e6 { + return fmt.Errorf("html: forward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + nBackward := 0 + for c := n.LastChild; c != nil; c = c.PrevSibling { + nBackward++ + if nBackward == 1e6 { + return fmt.Errorf("html: backward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + if n.Parent != nil { + if n.Parent == n { + return fmt.Errorf("html: inconsistent parent relationship") + } + if n.Parent == n.FirstChild { + return fmt.Errorf("html: inconsistent parent/first relationship") + } + if n.Parent == n.LastChild { + return fmt.Errorf("html: inconsistent parent/last relationship") + } + if n.Parent == n.PrevSibling { + return fmt.Errorf("html: inconsistent parent/prev relationship") + } + if n.Parent == n.NextSibling { + return fmt.Errorf("html: inconsistent parent/next relationship") + } + + parentHasNAsAChild := false + for c := n.Parent.FirstChild; c != nil; c = c.NextSibling { + if c == n { + parentHasNAsAChild = true + break + } + } + if !parentHasNAsAChild { + return fmt.Errorf("html: inconsistent parent/child relationship") + } + } + + if n.PrevSibling != nil && n.PrevSibling.NextSibling != n { + return fmt.Errorf("html: inconsistent prev/next relationship") + } + if n.NextSibling != nil && n.NextSibling.PrevSibling != n { + return fmt.Errorf("html: inconsistent next/prev relationship") + } + + if (n.FirstChild == nil) != (n.LastChild == nil) { + return fmt.Errorf("html: inconsistent first/last relationship") + } + if n.FirstChild != nil && n.FirstChild == n.LastChild { + // We have a sole child. + if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil { + return fmt.Errorf("html: inconsistent sole child's sibling relationship") + } + } + + seen := map[*Node]bool{} + + var last *Node + for c := n.FirstChild; c != nil; c = c.NextSibling { + if seen[c] { + return fmt.Errorf("html: inconsistent repeated child") + } + seen[c] = true + last = c + } + if last != n.LastChild { + return fmt.Errorf("html: inconsistent last relationship") + } + + var first *Node + for c := n.LastChild; c != nil; c = c.PrevSibling { + if !seen[c] { + return fmt.Errorf("html: inconsistent missing child") + } + delete(seen, c) + first = c + } + if first != n.FirstChild { + return fmt.Errorf("html: inconsistent first relationship") + } + + if len(seen) != 0 { + return fmt.Errorf("html: inconsistent forwards/backwards child list") + } + + return nil +} diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/parse.go b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/parse.go new file mode 100644 index 00000000..be4b2bf5 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/parse.go @@ -0,0 +1,2094 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "errors" + "fmt" + "io" + "strings" + + a "golang.org/x/net/html/atom" +) + +// A parser implements the HTML5 parsing algorithm: +// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction +type parser struct { + // tokenizer provides the tokens for the parser. + tokenizer *Tokenizer + // tok is the most recently read token. + tok Token + // Self-closing tags like
    are treated as start tags, except that + // hasSelfClosingToken is set while they are being processed. + hasSelfClosingToken bool + // doc is the document root element. + doc *Node + // The stack of open elements (section 12.2.3.2) and active formatting + // elements (section 12.2.3.3). + oe, afe nodeStack + // Element pointers (section 12.2.3.4). + head, form *Node + // Other parsing state flags (section 12.2.3.5). + scripting, framesetOK bool + // im is the current insertion mode. + im insertionMode + // originalIM is the insertion mode to go back to after completing a text + // or inTableText insertion mode. + originalIM insertionMode + // fosterParenting is whether new elements should be inserted according to + // the foster parenting rules (section 12.2.5.3). + fosterParenting bool + // quirks is whether the parser is operating in "quirks mode." + quirks bool + // fragment is whether the parser is parsing an HTML fragment. + fragment bool + // context is the context element when parsing an HTML fragment + // (section 12.4). + context *Node +} + +func (p *parser) top() *Node { + if n := p.oe.top(); n != nil { + return n + } + return p.doc +} + +// Stop tags for use in popUntil. These come from section 12.2.3.2. +var ( + defaultScopeStopTags = map[string][]a.Atom{ + "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, + "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, + "svg": {a.Desc, a.ForeignObject, a.Title}, + } +) + +type scope int + +const ( + defaultScope scope = iota + listItemScope + buttonScope + tableScope + tableRowScope + tableBodyScope + selectScope +) + +// popUntil pops the stack of open elements at the highest element whose tag +// is in matchTags, provided there is no higher element in the scope's stop +// tags (as defined in section 12.2.3.2). It returns whether or not there was +// such an element. If there was not, popUntil leaves the stack unchanged. +// +// For example, the set of stop tags for table scope is: "html", "table". If +// the stack was: +// ["html", "body", "font", "table", "b", "i", "u"] +// then popUntil(tableScope, "font") would return false, but +// popUntil(tableScope, "i") would return true and the stack would become: +// ["html", "body", "font", "table", "b"] +// +// If an element's tag is in both the stop tags and matchTags, then the stack +// will be popped and the function returns true (provided, of course, there was +// no higher element in the stack that was also in the stop tags). For example, +// popUntil(tableScope, "table") returns true and leaves: +// ["html", "body", "font"] +func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { + if i := p.indexOfElementInScope(s, matchTags...); i != -1 { + p.oe = p.oe[:i] + return true + } + return false +} + +// indexOfElementInScope returns the index in p.oe of the highest element whose +// tag is in matchTags that is in scope. If no matching element is in scope, it +// returns -1. +func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + if p.oe[i].Namespace == "" { + for _, t := range matchTags { + if t == tagAtom { + return i + } + } + switch s { + case defaultScope: + // No-op. + case listItemScope: + if tagAtom == a.Ol || tagAtom == a.Ul { + return -1 + } + case buttonScope: + if tagAtom == a.Button { + return -1 + } + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table { + return -1 + } + case selectScope: + if tagAtom != a.Optgroup && tagAtom != a.Option { + return -1 + } + default: + panic("unreachable") + } + } + switch s { + case defaultScope, listItemScope, buttonScope: + for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { + if t == tagAtom { + return -1 + } + } + } + } + return -1 +} + +// elementInScope is like popUntil, except that it doesn't modify the stack of +// open elements. +func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { + return p.indexOfElementInScope(s, matchTags...) != -1 +} + +// clearStackToContext pops elements off the stack of open elements until a +// scope-defined element is found. +func (p *parser) clearStackToContext(s scope) { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + switch s { + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table { + p.oe = p.oe[:i+1] + return + } + case tableRowScope: + if tagAtom == a.Html || tagAtom == a.Tr { + p.oe = p.oe[:i+1] + return + } + case tableBodyScope: + if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { + p.oe = p.oe[:i+1] + return + } + default: + panic("unreachable") + } + } +} + +// generateImpliedEndTags pops nodes off the stack of open elements as long as +// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. +// If exceptions are specified, nodes with that name will not be popped off. +func (p *parser) generateImpliedEndTags(exceptions ...string) { + var i int +loop: + for i = len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if n.Type == ElementNode { + switch n.DataAtom { + case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: + for _, except := range exceptions { + if n.Data == except { + break loop + } + } + continue + } + } + break + } + + p.oe = p.oe[:i+1] +} + +// addChild adds a child node n to the top element, and pushes n onto the stack +// of open elements if it is an element node. +func (p *parser) addChild(n *Node) { + if p.shouldFosterParent() { + p.fosterParent(n) + } else { + p.top().AppendChild(n) + } + + if n.Type == ElementNode { + p.oe = append(p.oe, n) + } +} + +// shouldFosterParent returns whether the next node to be added should be +// foster parented. +func (p *parser) shouldFosterParent() bool { + if p.fosterParenting { + switch p.top().DataAtom { + case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: + return true + } + } + return false +} + +// fosterParent adds a child node according to the foster parenting rules. +// Section 12.2.5.3, "foster parenting". +func (p *parser) fosterParent(n *Node) { + var table, parent, prev *Node + var i int + for i = len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].DataAtom == a.Table { + table = p.oe[i] + break + } + } + + if table == nil { + // The foster parent is the html element. + parent = p.oe[0] + } else { + parent = table.Parent + } + if parent == nil { + parent = p.oe[i-1] + } + + if table != nil { + prev = table.PrevSibling + } else { + prev = parent.LastChild + } + if prev != nil && prev.Type == TextNode && n.Type == TextNode { + prev.Data += n.Data + return + } + + parent.InsertBefore(n, table) +} + +// addText adds text to the preceding node if it is a text node, or else it +// calls addChild with a new text node. +func (p *parser) addText(text string) { + if text == "" { + return + } + + if p.shouldFosterParent() { + p.fosterParent(&Node{ + Type: TextNode, + Data: text, + }) + return + } + + t := p.top() + if n := t.LastChild; n != nil && n.Type == TextNode { + n.Data += text + return + } + p.addChild(&Node{ + Type: TextNode, + Data: text, + }) +} + +// addElement adds a child element based on the current token. +func (p *parser) addElement() { + p.addChild(&Node{ + Type: ElementNode, + DataAtom: p.tok.DataAtom, + Data: p.tok.Data, + Attr: p.tok.Attr, + }) +} + +// Section 12.2.3.3. +func (p *parser) addFormattingElement() { + tagAtom, attr := p.tok.DataAtom, p.tok.Attr + p.addElement() + + // Implement the Noah's Ark clause, but with three per family instead of two. + identicalElements := 0 +findIdenticalElements: + for i := len(p.afe) - 1; i >= 0; i-- { + n := p.afe[i] + if n.Type == scopeMarkerNode { + break + } + if n.Type != ElementNode { + continue + } + if n.Namespace != "" { + continue + } + if n.DataAtom != tagAtom { + continue + } + if len(n.Attr) != len(attr) { + continue + } + compareAttributes: + for _, t0 := range n.Attr { + for _, t1 := range attr { + if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { + // Found a match for this attribute, continue with the next attribute. + continue compareAttributes + } + } + // If we get here, there is no attribute that matches a. + // Therefore the element is not identical to the new one. + continue findIdenticalElements + } + + identicalElements++ + if identicalElements >= 3 { + p.afe.remove(n) + } + } + + p.afe = append(p.afe, p.top()) +} + +// Section 12.2.3.3. +func (p *parser) clearActiveFormattingElements() { + for { + n := p.afe.pop() + if len(p.afe) == 0 || n.Type == scopeMarkerNode { + return + } + } +} + +// Section 12.2.3.3. +func (p *parser) reconstructActiveFormattingElements() { + n := p.afe.top() + if n == nil { + return + } + if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { + return + } + i := len(p.afe) - 1 + for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { + if i == 0 { + i = -1 + break + } + i-- + n = p.afe[i] + } + for { + i++ + clone := p.afe[i].clone() + p.addChild(clone) + p.afe[i] = clone + if i == len(p.afe)-1 { + break + } + } +} + +// Section 12.2.4. +func (p *parser) acknowledgeSelfClosingTag() { + p.hasSelfClosingToken = false +} + +// An insertion mode (section 12.2.3.1) is the state transition function from +// a particular state in the HTML5 parser's state machine. It updates the +// parser's fields depending on parser.tok (where ErrorToken means EOF). +// It returns whether the token was consumed. +type insertionMode func(*parser) bool + +// setOriginalIM sets the insertion mode to return to after completing a text or +// inTableText insertion mode. +// Section 12.2.3.1, "using the rules for". +func (p *parser) setOriginalIM() { + if p.originalIM != nil { + panic("html: bad parser state: originalIM was set twice") + } + p.originalIM = p.im +} + +// Section 12.2.3.1, "reset the insertion mode". +func (p *parser) resetInsertionMode() { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if i == 0 && p.context != nil { + n = p.context + } + + switch n.DataAtom { + case a.Select: + p.im = inSelectIM + case a.Td, a.Th: + p.im = inCellIM + case a.Tr: + p.im = inRowIM + case a.Tbody, a.Thead, a.Tfoot: + p.im = inTableBodyIM + case a.Caption: + p.im = inCaptionIM + case a.Colgroup: + p.im = inColumnGroupIM + case a.Table: + p.im = inTableIM + case a.Head: + p.im = inBodyIM + case a.Body: + p.im = inBodyIM + case a.Frameset: + p.im = inFramesetIM + case a.Html: + p.im = beforeHeadIM + default: + continue + } + return + } + p.im = inBodyIM +} + +const whitespace = " \t\r\n\f" + +// Section 12.2.5.4.1. +func initialIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + n, quirks := parseDoctype(p.tok.Data) + p.doc.AppendChild(n) + p.quirks = quirks + p.im = beforeHTMLIM + return true + } + p.quirks = true + p.im = beforeHTMLIM + return false +} + +// Section 12.2.5.4.2. +func beforeHTMLIM(p *parser) bool { + switch p.tok.Type { + case DoctypeToken: + // Ignore the token. + return true + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + if p.tok.DataAtom == a.Html { + p.addElement() + p.im = beforeHeadIM + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false +} + +// Section 12.2.5.4.3. +func beforeHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Head: + p.addElement() + p.head = p.top() + p.im = inHeadIM + return true + case a.Html: + return inBodyIM(p) + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false +} + +// Section 12.2.5.4.4. +func inHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: + p.addElement() + p.oe.pop() + p.acknowledgeSelfClosingTag() + return true + case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: + p.addElement() + p.setOriginalIM() + p.im = textIM + return true + case a.Head: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head: + n := p.oe.pop() + if n.DataAtom != a.Head { + panic("html: bad parser state: element not found, in the in-head insertion mode") + } + p.im = afterHeadIM + return true + case a.Body, a.Html, a.Br: + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false +} + +// Section 12.2.5.4.6. +func afterHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Body: + p.addElement() + p.framesetOK = false + p.im = inBodyIM + return true + case a.Frameset: + p.addElement() + p.im = inFramesetIM + return true + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: + p.oe = append(p.oe, p.head) + defer p.oe.remove(p.head) + return inHeadIM(p) + case a.Head: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Body, a.Html, a.Br: + // Drop down to creating an implied tag. + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) + p.framesetOK = true + return false +} + +// copyAttributes copies attributes of src not found on dst to dst. +func copyAttributes(dst *Node, src Token) { + if len(src.Attr) == 0 { + return + } + attr := map[string]string{} + for _, t := range dst.Attr { + attr[t.Key] = t.Val + } + for _, t := range src.Attr { + if _, ok := attr[t.Key]; !ok { + dst.Attr = append(dst.Attr, t) + attr[t.Key] = t.Val + } + } +} + +// Section 12.2.5.4.7. +func inBodyIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + d := p.tok.Data + switch n := p.oe.top(); n.DataAtom { + case a.Pre, a.Listing: + if n.FirstChild == nil { + // Ignore a newline at the start of a
     block.
    +				if d != "" && d[0] == '\r' {
    +					d = d[1:]
    +				}
    +				if d != "" && d[0] == '\n' {
    +					d = d[1:]
    +				}
    +			}
    +		}
    +		d = strings.Replace(d, "\x00", "", -1)
    +		if d == "" {
    +			return true
    +		}
    +		p.reconstructActiveFormattingElements()
    +		p.addText(d)
    +		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
    +			// There were non-whitespace characters inserted.
    +			p.framesetOK = false
    +		}
    +	case StartTagToken:
    +		switch p.tok.DataAtom {
    +		case a.Html:
    +			copyAttributes(p.oe[0], p.tok)
    +		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
    +			return inHeadIM(p)
    +		case a.Body:
    +			if len(p.oe) >= 2 {
    +				body := p.oe[1]
    +				if body.Type == ElementNode && body.DataAtom == a.Body {
    +					p.framesetOK = false
    +					copyAttributes(body, p.tok)
    +				}
    +			}
    +		case a.Frameset:
    +			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
    +				// Ignore the token.
    +				return true
    +			}
    +			body := p.oe[1]
    +			if body.Parent != nil {
    +				body.Parent.RemoveChild(body)
    +			}
    +			p.oe = p.oe[:1]
    +			p.addElement()
    +			p.im = inFramesetIM
    +			return true
    +		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    +			p.popUntil(buttonScope, a.P)
    +			switch n := p.top(); n.DataAtom {
    +			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    +				p.oe.pop()
    +			}
    +			p.addElement()
    +		case a.Pre, a.Listing:
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +			// The newline, if any, will be dealt with by the TextToken case.
    +			p.framesetOK = false
    +		case a.Form:
    +			if p.form == nil {
    +				p.popUntil(buttonScope, a.P)
    +				p.addElement()
    +				p.form = p.top()
    +			}
    +		case a.Li:
    +			p.framesetOK = false
    +			for i := len(p.oe) - 1; i >= 0; i-- {
    +				node := p.oe[i]
    +				switch node.DataAtom {
    +				case a.Li:
    +					p.oe = p.oe[:i]
    +				case a.Address, a.Div, a.P:
    +					continue
    +				default:
    +					if !isSpecialElement(node) {
    +						continue
    +					}
    +				}
    +				break
    +			}
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +		case a.Dd, a.Dt:
    +			p.framesetOK = false
    +			for i := len(p.oe) - 1; i >= 0; i-- {
    +				node := p.oe[i]
    +				switch node.DataAtom {
    +				case a.Dd, a.Dt:
    +					p.oe = p.oe[:i]
    +				case a.Address, a.Div, a.P:
    +					continue
    +				default:
    +					if !isSpecialElement(node) {
    +						continue
    +					}
    +				}
    +				break
    +			}
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +		case a.Plaintext:
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +		case a.Button:
    +			p.popUntil(defaultScope, a.Button)
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +			p.framesetOK = false
    +		case a.A:
    +			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
    +				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
    +					p.inBodyEndTagFormatting(a.A)
    +					p.oe.remove(n)
    +					p.afe.remove(n)
    +					break
    +				}
    +			}
    +			p.reconstructActiveFormattingElements()
    +			p.addFormattingElement()
    +		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
    +			p.reconstructActiveFormattingElements()
    +			p.addFormattingElement()
    +		case a.Nobr:
    +			p.reconstructActiveFormattingElements()
    +			if p.elementInScope(defaultScope, a.Nobr) {
    +				p.inBodyEndTagFormatting(a.Nobr)
    +				p.reconstructActiveFormattingElements()
    +			}
    +			p.addFormattingElement()
    +		case a.Applet, a.Marquee, a.Object:
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +			p.afe = append(p.afe, &scopeMarker)
    +			p.framesetOK = false
    +		case a.Table:
    +			if !p.quirks {
    +				p.popUntil(buttonScope, a.P)
    +			}
    +			p.addElement()
    +			p.framesetOK = false
    +			p.im = inTableIM
    +			return true
    +		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +			p.oe.pop()
    +			p.acknowledgeSelfClosingTag()
    +			if p.tok.DataAtom == a.Input {
    +				for _, t := range p.tok.Attr {
    +					if t.Key == "type" {
    +						if strings.ToLower(t.Val) == "hidden" {
    +							// Skip setting framesetOK = false
    +							return true
    +						}
    +					}
    +				}
    +			}
    +			p.framesetOK = false
    +		case a.Param, a.Source, a.Track:
    +			p.addElement()
    +			p.oe.pop()
    +			p.acknowledgeSelfClosingTag()
    +		case a.Hr:
    +			p.popUntil(buttonScope, a.P)
    +			p.addElement()
    +			p.oe.pop()
    +			p.acknowledgeSelfClosingTag()
    +			p.framesetOK = false
    +		case a.Image:
    +			p.tok.DataAtom = a.Img
    +			p.tok.Data = a.Img.String()
    +			return false
    +		case a.Isindex:
    +			if p.form != nil {
    +				// Ignore the token.
    +				return true
    +			}
    +			action := ""
    +			prompt := "This is a searchable index. Enter search keywords: "
    +			attr := []Attribute{{Key: "name", Val: "isindex"}}
    +			for _, t := range p.tok.Attr {
    +				switch t.Key {
    +				case "action":
    +					action = t.Val
    +				case "name":
    +					// Ignore the attribute.
    +				case "prompt":
    +					prompt = t.Val
    +				default:
    +					attr = append(attr, t)
    +				}
    +			}
    +			p.acknowledgeSelfClosingTag()
    +			p.popUntil(buttonScope, a.P)
    +			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
    +			if action != "" {
    +				p.form.Attr = []Attribute{{Key: "action", Val: action}}
    +			}
    +			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
    +			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
    +			p.addText(prompt)
    +			p.addChild(&Node{
    +				Type:     ElementNode,
    +				DataAtom: a.Input,
    +				Data:     a.Input.String(),
    +				Attr:     attr,
    +			})
    +			p.oe.pop()
    +			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
    +			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
    +			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
    +		case a.Textarea:
    +			p.addElement()
    +			p.setOriginalIM()
    +			p.framesetOK = false
    +			p.im = textIM
    +		case a.Xmp:
    +			p.popUntil(buttonScope, a.P)
    +			p.reconstructActiveFormattingElements()
    +			p.framesetOK = false
    +			p.addElement()
    +			p.setOriginalIM()
    +			p.im = textIM
    +		case a.Iframe:
    +			p.framesetOK = false
    +			p.addElement()
    +			p.setOriginalIM()
    +			p.im = textIM
    +		case a.Noembed, a.Noscript:
    +			p.addElement()
    +			p.setOriginalIM()
    +			p.im = textIM
    +		case a.Select:
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +			p.framesetOK = false
    +			p.im = inSelectIM
    +			return true
    +		case a.Optgroup, a.Option:
    +			if p.top().DataAtom == a.Option {
    +				p.oe.pop()
    +			}
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +		case a.Rp, a.Rt:
    +			if p.elementInScope(defaultScope, a.Ruby) {
    +				p.generateImpliedEndTags()
    +			}
    +			p.addElement()
    +		case a.Math, a.Svg:
    +			p.reconstructActiveFormattingElements()
    +			if p.tok.DataAtom == a.Math {
    +				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
    +			} else {
    +				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
    +			}
    +			adjustForeignAttributes(p.tok.Attr)
    +			p.addElement()
    +			p.top().Namespace = p.tok.Data
    +			if p.hasSelfClosingToken {
    +				p.oe.pop()
    +				p.acknowledgeSelfClosingTag()
    +			}
    +			return true
    +		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
    +			// Ignore the token.
    +		default:
    +			p.reconstructActiveFormattingElements()
    +			p.addElement()
    +		}
    +	case EndTagToken:
    +		switch p.tok.DataAtom {
    +		case a.Body:
    +			if p.elementInScope(defaultScope, a.Body) {
    +				p.im = afterBodyIM
    +			}
    +		case a.Html:
    +			if p.elementInScope(defaultScope, a.Body) {
    +				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
    +				return false
    +			}
    +			return true
    +		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
    +			p.popUntil(defaultScope, p.tok.DataAtom)
    +		case a.Form:
    +			node := p.form
    +			p.form = nil
    +			i := p.indexOfElementInScope(defaultScope, a.Form)
    +			if node == nil || i == -1 || p.oe[i] != node {
    +				// Ignore the token.
    +				return true
    +			}
    +			p.generateImpliedEndTags()
    +			p.oe.remove(node)
    +		case a.P:
    +			if !p.elementInScope(buttonScope, a.P) {
    +				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
    +			}
    +			p.popUntil(buttonScope, a.P)
    +		case a.Li:
    +			p.popUntil(listItemScope, a.Li)
    +		case a.Dd, a.Dt:
    +			p.popUntil(defaultScope, p.tok.DataAtom)
    +		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    +			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
    +		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
    +			p.inBodyEndTagFormatting(p.tok.DataAtom)
    +		case a.Applet, a.Marquee, a.Object:
    +			if p.popUntil(defaultScope, p.tok.DataAtom) {
    +				p.clearActiveFormattingElements()
    +			}
    +		case a.Br:
    +			p.tok.Type = StartTagToken
    +			return false
    +		default:
    +			p.inBodyEndTagOther(p.tok.DataAtom)
    +		}
    +	case CommentToken:
    +		p.addChild(&Node{
    +			Type: CommentNode,
    +			Data: p.tok.Data,
    +		})
    +	}
    +
    +	return true
    +}
    +
    +func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
    +	// This is the "adoption agency" algorithm, described at
    +	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
    +
    +	// TODO: this is a fairly literal line-by-line translation of that algorithm.
    +	// Once the code successfully parses the comprehensive test suite, we should
    +	// refactor this code to be more idiomatic.
    +
    +	// Steps 1-4. The outer loop.
    +	for i := 0; i < 8; i++ {
    +		// Step 5. Find the formatting element.
    +		var formattingElement *Node
    +		for j := len(p.afe) - 1; j >= 0; j-- {
    +			if p.afe[j].Type == scopeMarkerNode {
    +				break
    +			}
    +			if p.afe[j].DataAtom == tagAtom {
    +				formattingElement = p.afe[j]
    +				break
    +			}
    +		}
    +		if formattingElement == nil {
    +			p.inBodyEndTagOther(tagAtom)
    +			return
    +		}
    +		feIndex := p.oe.index(formattingElement)
    +		if feIndex == -1 {
    +			p.afe.remove(formattingElement)
    +			return
    +		}
    +		if !p.elementInScope(defaultScope, tagAtom) {
    +			// Ignore the tag.
    +			return
    +		}
    +
    +		// Steps 9-10. Find the furthest block.
    +		var furthestBlock *Node
    +		for _, e := range p.oe[feIndex:] {
    +			if isSpecialElement(e) {
    +				furthestBlock = e
    +				break
    +			}
    +		}
    +		if furthestBlock == nil {
    +			e := p.oe.pop()
    +			for e != formattingElement {
    +				e = p.oe.pop()
    +			}
    +			p.afe.remove(e)
    +			return
    +		}
    +
    +		// Steps 11-12. Find the common ancestor and bookmark node.
    +		commonAncestor := p.oe[feIndex-1]
    +		bookmark := p.afe.index(formattingElement)
    +
    +		// Step 13. The inner loop. Find the lastNode to reparent.
    +		lastNode := furthestBlock
    +		node := furthestBlock
    +		x := p.oe.index(node)
    +		// Steps 13.1-13.2
    +		for j := 0; j < 3; j++ {
    +			// Step 13.3.
    +			x--
    +			node = p.oe[x]
    +			// Step 13.4 - 13.5.
    +			if p.afe.index(node) == -1 {
    +				p.oe.remove(node)
    +				continue
    +			}
    +			// Step 13.6.
    +			if node == formattingElement {
    +				break
    +			}
    +			// Step 13.7.
    +			clone := node.clone()
    +			p.afe[p.afe.index(node)] = clone
    +			p.oe[p.oe.index(node)] = clone
    +			node = clone
    +			// Step 13.8.
    +			if lastNode == furthestBlock {
    +				bookmark = p.afe.index(node) + 1
    +			}
    +			// Step 13.9.
    +			if lastNode.Parent != nil {
    +				lastNode.Parent.RemoveChild(lastNode)
    +			}
    +			node.AppendChild(lastNode)
    +			// Step 13.10.
    +			lastNode = node
    +		}
    +
    +		// Step 14. Reparent lastNode to the common ancestor,
    +		// or for misnested table nodes, to the foster parent.
    +		if lastNode.Parent != nil {
    +			lastNode.Parent.RemoveChild(lastNode)
    +		}
    +		switch commonAncestor.DataAtom {
    +		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
    +			p.fosterParent(lastNode)
    +		default:
    +			commonAncestor.AppendChild(lastNode)
    +		}
    +
    +		// Steps 15-17. Reparent nodes from the furthest block's children
    +		// to a clone of the formatting element.
    +		clone := formattingElement.clone()
    +		reparentChildren(clone, furthestBlock)
    +		furthestBlock.AppendChild(clone)
    +
    +		// Step 18. Fix up the list of active formatting elements.
    +		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
    +			// Move the bookmark with the rest of the list.
    +			bookmark--
    +		}
    +		p.afe.remove(formattingElement)
    +		p.afe.insert(bookmark, clone)
    +
    +		// Step 19. Fix up the stack of open elements.
    +		p.oe.remove(formattingElement)
    +		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
    +	}
    +}
    +
    +// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
    +// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
    +// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
    +func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
    +	for i := len(p.oe) - 1; i >= 0; i-- {
    +		if p.oe[i].DataAtom == tagAtom {
    +			p.oe = p.oe[:i]
    +			break
    +		}
    +		if isSpecialElement(p.oe[i]) {
    +			break
    +		}
    +	}
    +}
    +
    +// Section 12.2.5.4.8.
    +func textIM(p *parser) bool {
    +	switch p.tok.Type {
    +	case ErrorToken:
    +		p.oe.pop()
    +	case TextToken:
    +		d := p.tok.Data
    +		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
    +			// Ignore a newline at the start of a -->
    +#errors
    +#document
    +| 
    +|   
    +|   
    +|     -->
    +#errors
    +#document
    +| 
    +|   
    +|   
    +|     
    +#errors
    +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
    +#document
    +| 
    +|   
    +|   
    +|     
    +#errors
    +Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
    +Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
    +Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
    +Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
    +Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
    +Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
    +Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
    +Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
    +Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
    +Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
    +Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
    +Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
    +Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
    +Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
    +Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
    +Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
    +Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
    +Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
    +Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
    +Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
    +Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
    +Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
    +Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
    +Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
    +Line: 1 Col: 140 This element (img) has no end tag.
    +Line: 1 Col: 148 Unexpected end tag (title). Ignored.
    +Line: 1 Col: 155 Unexpected end tag (span). Ignored.
    +Line: 1 Col: 163 Unexpected end tag (style). Ignored.
    +Line: 1 Col: 172 Unexpected end tag (script). Ignored.
    +Line: 1 Col: 180 Unexpected end tag (table). Ignored.
    +Line: 1 Col: 185 Unexpected end tag (th). Ignored.
    +Line: 1 Col: 190 Unexpected end tag (td). Ignored.
    +Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
    +Line: 1 Col: 203 This element (frame) has no end tag.
    +Line: 1 Col: 210 This element (area) has no end tag.
    +Line: 1 Col: 217 Unexpected end tag (link). Ignored.
    +Line: 1 Col: 225 This element (param) has no end tag.
    +Line: 1 Col: 230 This element (hr) has no end tag.
    +Line: 1 Col: 238 This element (input) has no end tag.
    +Line: 1 Col: 244 Unexpected end tag (col). Ignored.
    +Line: 1 Col: 251 Unexpected end tag (base). Ignored.
    +Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
    +Line: 1 Col: 269 This element (basefont) has no end tag.
    +Line: 1 Col: 279 This element (bgsound) has no end tag.
    +Line: 1 Col: 287 This element (embed) has no end tag.
    +Line: 1 Col: 296 This element (spacer) has no end tag.
    +Line: 1 Col: 300 Unexpected end tag (p). Ignored.
    +Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
    +Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
    +Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
    +Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
    +Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
    +Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
    +Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
    +Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
    +Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
    +Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
    +Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
    +Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
    +Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
    +Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
    +Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
    +Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
    +Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
    +Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
    +Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
    +Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
    +Line: 1 Col: 460 This element (wbr) has no end tag.
    +Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
    +Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
    +Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
    +Line: 1 Col: 513 Unexpected end tag (html). Ignored.
    +Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
    +Line: 1 Col: 520 Unexpected end tag (head). Ignored.
    +Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
    +Line: 1 Col: 537 This element (image) has no end tag.
    +Line: 1 Col: 547 This element (isindex) has no end tag.
    +Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
    +Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
    +Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
    +Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
    +Line: 1 Col: 599 Unexpected end tag (option). Ignored.
    +Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
    +Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
    +#document
    +| 
    +|   
    +|   
    +|     
    +|

    + +#data +

    +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode. +Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode. +Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode. +Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode. +Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode. +Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode. +Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode. +Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode. +Line: 1 Col: 58 Unexpected end tag (blink). Ignored. +Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode. +Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode. +Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag. +Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode. +Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode. +Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode. +Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode. +Line: 1 Col: 99 Unexpected end tag (select). Ignored. +Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode. +Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag. +Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode. +Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag. +Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode. +Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag. +Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode. +Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag. +Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode. +Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag. +Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode. +Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag. +Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored. +Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode. +Line: 1 Col: 141 Unexpected end tag (br). Treated as br element. +Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode. +Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode. +Line: 1 Col: 151 This element (img) has no end tag. +Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode. +Line: 1 Col: 159 Unexpected end tag (title). Ignored. +Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode. +Line: 1 Col: 166 Unexpected end tag (span). Ignored. +Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode. +Line: 1 Col: 174 Unexpected end tag (style). Ignored. +Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode. +Line: 1 Col: 183 Unexpected end tag (script). Ignored. +Line: 1 Col: 196 Unexpected end tag (th). Ignored. +Line: 1 Col: 201 Unexpected end tag (td). Ignored. +Line: 1 Col: 206 Unexpected end tag (tr). Ignored. +Line: 1 Col: 214 This element (frame) has no end tag. +Line: 1 Col: 221 This element (area) has no end tag. +Line: 1 Col: 228 Unexpected end tag (link). Ignored. +Line: 1 Col: 236 This element (param) has no end tag. +Line: 1 Col: 241 This element (hr) has no end tag. +Line: 1 Col: 249 This element (input) has no end tag. +Line: 1 Col: 255 Unexpected end tag (col). Ignored. +Line: 1 Col: 262 Unexpected end tag (base). Ignored. +Line: 1 Col: 269 Unexpected end tag (meta). Ignored. +Line: 1 Col: 280 This element (basefont) has no end tag. +Line: 1 Col: 290 This element (bgsound) has no end tag. +Line: 1 Col: 298 This element (embed) has no end tag. +Line: 1 Col: 307 This element (spacer) has no end tag. +Line: 1 Col: 311 Unexpected end tag (p). Ignored. +Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag. +Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag. +Line: 1 Col: 331 Unexpected end tag (caption). Ignored. +Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 350 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 366 Unexpected end tag (thead). Ignored. +Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag. +Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag. +Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag. +Line: 1 Col: 404 Unexpected end tag (dir). Ignored. +Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag. +Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag. +Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag. +Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag. +Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag. +Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag. +Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag. +Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 471 This element (wbr) has no end tag. +Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag. +Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag. +Line: 1 Col: 524 Unexpected end tag (html). Ignored. +Line: 1 Col: 524 Unexpected end tag (frameset). Ignored. +Line: 1 Col: 531 Unexpected end tag (head). Ignored. +Line: 1 Col: 540 Unexpected end tag (iframe). Ignored. +Line: 1 Col: 548 This element (image) has no end tag. +Line: 1 Col: 558 This element (isindex) has no end tag. +Line: 1 Col: 568 Unexpected end tag (noembed). Ignored. +Line: 1 Col: 579 Unexpected end tag (noframes). Ignored. +Line: 1 Col: 590 Unexpected end tag (noscript). Ignored. +Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored. +Line: 1 Col: 610 Unexpected end tag (option). Ignored. +Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored. +Line: 1 Col: 633 Unexpected end tag (textarea). Ignored. +#document +| +| +| +|
    +| +| +| +|

    + +#data + +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 10 Expected closing tag. Unexpected end of file. +#document +| +| +| diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests10.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests10.dat new file mode 100644 index 00000000..4f8df86f --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests10.dat @@ -0,0 +1,799 @@ +#data + +#errors +#document +| +| +| +| +| + +#data +a +#errors +29: Bogus comment +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +35: Stray “svg” start tag. +42: Stray end tag “svg” +#document +| +| +| +| +| +#errors +43: Stray “svg” start tag. +50: Stray end tag “svg” +#document +| +| +| +| +|

    +#errors +34: Start tag “svg” seen in “table”. +41: Stray end tag “svg”. +#document +| +| +| +| +| +| + +#data +
    foo
    +#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +53: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| + +#data +
    foobar
    +#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +58: Stray end tag “g”. +65: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| + +#data +
    foobar
    +#errors +41: Start tag “svg” seen in “table”. +53: Stray end tag “g”. +65: Stray end tag “g”. +72: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| + +#data +
    foobar
    +#errors +45: Start tag “svg” seen in “table”. +57: Stray end tag “g”. +69: Stray end tag “g”. +76: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| +| + +#data +
    foobar
    +#errors +#document +| +| +| +| +| +| +| +|
    +| +| +| "foo" +| +| "bar" + +#data +
    foobar

    baz

    +#errors +#document +| +| +| +| +| +| +| +|
    +| +| +| "foo" +| +| "bar" +|

    +| "baz" + +#data +
    foobar

    baz

    +#errors +#document +| +| +| +| +| +|
    +| +| +| "foo" +| +| "bar" +|

    +| "baz" + +#data +
    foobar

    baz

    quux +#errors +70: HTML start tag “p” in a foreign namespace context. +81: “table” closed but “caption” was still open. +#document +| +| +| +| +| +|
    +| +| +| "foo" +| +| "bar" +|

    +| "baz" +|

    +| "quux" + +#data +
    foobarbaz

    quux +#errors +78: “table” closed but “caption” was still open. +78: Unclosed elements on stack. +#document +| +| +| +| +| +|
    +| +| +| "foo" +| +| "bar" +| "baz" +|

    +| "quux" + +#data +foobar

    baz

    quux +#errors +44: Start tag “svg” seen in “table”. +56: Stray end tag “g”. +68: Stray end tag “g”. +71: HTML start tag “p” in a foreign namespace context. +71: Start tag “p” seen in “table”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

    +| "baz" +| +| +|

    +| "quux" + +#data +

    quux +#errors +50: Stray “svg” start tag. +54: Stray “g” start tag. +62: Stray end tag “g” +66: Stray “g” start tag. +74: Stray end tag “g” +77: Stray “p” start tag. +88: “table” end tag with “select” open. +#document +| +| +| +| +| +| +| +|
    +|

    quux +#errors +36: Start tag “select” seen in “table”. +42: Stray “svg” start tag. +46: Stray “g” start tag. +54: Stray end tag “g” +58: Stray “g” start tag. +66: Stray end tag “g” +69: Stray “p” start tag. +80: “table” end tag with “select” open. +#document +| +| +| +| +| +|

    +| "quux" + +#data +foobar

    baz +#errors +41: Stray “svg” start tag. +68: HTML start tag “p” in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

    +| "baz" + +#data +foobar

    baz +#errors +34: Stray “svg” start tag. +61: HTML start tag “p” in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

    +| "baz" + +#data +

    +#errors +31: Stray “svg” start tag. +35: Stray “g” start tag. +40: Stray end tag “g” +44: Stray “g” start tag. +49: Stray end tag “g” +52: Stray “p” start tag. +58: Stray “span” start tag. +58: End of file seen and there were open elements. +#document +| +| +| +| + +#data +

    +#errors +42: Stray “svg” start tag. +46: Stray “g” start tag. +51: Stray end tag “g” +55: Stray “g” start tag. +60: Stray end tag “g” +63: Stray “p” start tag. +69: Stray “span” start tag. +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| +| xlink href="foo" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data +bar +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" +| "bar" + +#data + +#errors +#document +| +| +| +| + +#data +

    a +#errors +#document +| +| +| +|
    +| +| "a" + +#data +
    a +#errors +#document +| +| +| +|
    +| +| +| "a" + +#data +
    +#errors +#document +| +| +| +|
    +| +| +| + +#data +
    a +#errors +#document +| +| +| +|
    +| +| +| +| +| "a" + +#data +

    a +#errors +#document +| +| +| +|

    +| +| +| +|

    +| "a" + +#data +
      a +#errors +40: HTML start tag “ul” in a foreign namespace context. +41: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +|
      +| +|
        +| "a" + +#data +
          a +#errors +35: HTML start tag “ul” in a foreign namespace context. +36: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +| +|
            +| "a" + +#data +

            +#errors +#document +| +| +| +| +|

            +| +| +|

            + +#data +

            +#errors +#document +| +| +| +| +|

            +| +| +|

            + +#data +

            +#errors +#document +| +| +| +|

            +| +| +| +|

            +|

            + +#data +
            +#errors +#document +| +| +| +| +| +|
            +| +|
            +| +| + +#data +
            +#errors +#document +| +| +| +| +| +| +| +|
            +|
            +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data +

    +#errors +#document +| +| +| +| +|
    +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| + +#data +
    +#errors +#document +| +| +| +| +| +| +| +|
    +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests11.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests11.dat new file mode 100644 index 00000000..638cde47 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests11.dat @@ -0,0 +1,482 @@ +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributename="" +| attributetype="" +| basefrequency="" +| baseprofile="" +| calcmode="" +| clippathunits="" +| contentscripttype="" +| contentstyletype="" +| diffuseconstant="" +| edgemode="" +| externalresourcesrequired="" +| filterres="" +| filterunits="" +| glyphref="" +| gradienttransform="" +| gradientunits="" +| kernelmatrix="" +| kernelunitlength="" +| keypoints="" +| keysplines="" +| keytimes="" +| lengthadjust="" +| limitingconeangle="" +| markerheight="" +| markerunits="" +| markerwidth="" +| maskcontentunits="" +| maskunits="" +| numoctaves="" +| pathlength="" +| patterncontentunits="" +| patterntransform="" +| patternunits="" +| pointsatx="" +| pointsaty="" +| pointsatz="" +| preservealpha="" +| preserveaspectratio="" +| primitiveunits="" +| refx="" +| refy="" +| repeatcount="" +| repeatdur="" +| requiredextensions="" +| requiredfeatures="" +| specularconstant="" +| specularexponent="" +| spreadmethod="" +| startoffset="" +| stddeviation="" +| stitchtiles="" +| surfacescale="" +| systemlanguage="" +| tablevalues="" +| targetx="" +| targety="" +| textlength="" +| viewbox="" +| viewtarget="" +| xchannelselector="" +| ychannelselector="" +| zoomandpan="" + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests12.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests12.dat new file mode 100644 index 00000000..63107d27 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests12.dat @@ -0,0 +1,62 @@ +#data +

    foobazeggs

    spam

    quuxbar +#errors +#document +| +| +| +| +|

    +| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

    +| "spam" +| +| +| +|
    +| +| +| "quux" +| "bar" + +#data +foobazeggs

    spam
    quuxbar +#errors +#document +| +| +| +| +| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

    +| "spam" +| +| +| +|
    +| +| +| "quux" +| "bar" diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests14.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests14.dat new file mode 100644 index 00000000..b8713f88 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests14.dat @@ -0,0 +1,74 @@ +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| abc:def="gh" +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| xml:lang="bar" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| 789="012" +| +| + +#data + +#errors +#document +| +| +| +| +| 789="012" diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests15.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests15.dat new file mode 100644 index 00000000..6ce1c0d1 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests15.dat @@ -0,0 +1,208 @@ +#data +

    X +#errors +Line: 1 Col: 31 Unexpected end tag (p). Ignored. +Line: 1 Col: 36 Expected closing tag. Unexpected end of file. +#document +| +| +| +| +|

    +| +| +| +| +| +| +| " " +|

    +| "X" + +#data +

    +

    X +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end tag (p). Ignored. +Line: 2 Col: 4 Expected closing tag. Unexpected end of file. +#document +| +| +| +|

    +| +| +| +| +| +| +| " +" +|

    +| "X" + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| +| " " + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| + +#data + +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| + +#data +X +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| +| "X" + +#data +<!doctype html><table> X<meta></table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " X" +| <meta> +| <table> + +#data +<!doctype html><table> x</table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> + +#data +<!doctype html><table> x </table> +#errors +Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x " +| <table> + +#data +<!doctype html><table><tr> x</table> +#errors +Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table>X<style> <tr>x </style> </table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <style> +| " <tr>x " +| " " + +#data +<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div> +#errors +Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <a> +| "foo" +| <table> +| " " +| <tbody> +| <tr> +| <td> +| "bar" +| " " + +#data +<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes> +#errors +6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +13: Stray start tag “frame”. +21: Stray end tag “frame”. +29: Stray end tag “frame”. +39: “frameset” start tag after “body” already open. +105: End of file seen inside an [R]CDATA element. +105: End of file seen and there were open elements. +XXX: These errors are wrong, please fix me! +#document +| <html> +| <head> +| <frameset> +| <frame> +| <frameset> +| <frame> +| <noframes> +| "</frameset><noframes>" + +#data +<!DOCTYPE html><object></html> +#errors +1: Expected closing tag. Unexpected end of file +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests16.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests16.dat new file mode 100644 index 00000000..c8ef66f0 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests16.dat @@ -0,0 +1,2299 @@ +#data +<!doctype html><script> +#errors +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script>a +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<!doctype html><script>< +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<!doctype html><script></ +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<!doctype html><script></S +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<!doctype html><script></SC +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<!doctype html><script></SCR +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<!doctype html><script></SCRI +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<!doctype html><script></SCRIP +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script></s +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<!doctype html><script></sc +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<!doctype html><script></scr +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<!doctype html><script></scri +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<!doctype html><script></scrip +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script><! +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<!doctype html><script><!a +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<!doctype html><script><!- +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<!doctype html><script><!-a +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<!doctype html><script><!-- +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--a +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<!doctype html><script><!--< +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<!doctype html><script><!--<a +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<!doctype html><script><!--</ +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--<s +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<!doctype html><script><!--<script < +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<!doctype html><script><!--<script <a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<!doctype html><script><!--<script </ +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<!doctype html><script><!--<script </s +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 43 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<!doctype html><script><!--<script </scripta +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script> +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<!doctype html><script><!--<script </script/ +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<!doctype html><script><!--<script </script < +#errors +Line: 1 Col: 45 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<!doctype html><script><!--<script </script <a +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<!doctype html><script><!--<script </script </ +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script/ +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script - +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<!doctype html><script><!--<script -a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<!doctype html><script><!--<script -< +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -<" +| <body> + +#data +<!doctype html><script><!--<script -- +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<!doctype html><script><!--<script --a +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<!doctype html><script><!--<script --< +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --<" +| <body> + +#data +<!doctype html><script><!--<script --> +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script -->< +#errors +Line: 1 Col: 39 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<!doctype html><script><!--<script --></ +#errors +Line: 1 Col: 40 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script/ +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script><\/script>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<!doctype html><script><!--<script></scr'+'ipt>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>--><!--</script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-- ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- -></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- - ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<!doctype html><script><!--<script>--!></script>X +#errors +Line: 1 Col: 49 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<!doctype html><script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 59 Unexpected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<!doctype html><script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 57 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<!doctype html><style><!--<style></style>--></style> +#errors +Line: 1 Col: 52 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<!doctype html><style><!--</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<!doctype html><style><!--...</style>...--></style> +#errors +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<!doctype html><style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 66 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<!doctype html><style><!--...</style><!-- --><style>@import ...</style> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<!doctype html><style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 63 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<!doctype html><style>...<!--[if IE]><style>...</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<!doctype html><title><!--<title>--> +#errors +Line: 1 Col: 52 Unexpected end tag (title). +#document +| +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<!doctype html><title></title> +#errors +#document +| +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (title). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<!doctype html><noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 64 Unexpected end tag (noscript). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<!doctype html><noscript><!--</noscript>X<noscript>--></noscript> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<!doctype html><noscript><iframe></noscript>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<!doctype html><noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 64 Unexpected end tag (noframes). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<!doctype html><noframes><body><script><!--...</script></body></noframes></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<!doctype html><textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 64 Unexpected end tag (textarea). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<!doctype html><textarea></textarea></textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<!doctype html><textarea><</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<" + +#data +<!doctype html><textarea>a<b</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "a<b" + +#data +<!doctype html><iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 56 Unexpected end tag (iframe). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<!doctype html><iframe>...<!--X->...<!--/X->...</iframe> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<!doctype html><xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 44 Unexpected end tag (xmp). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<!doctype html><noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 60 Unexpected end tag (noembed). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script>a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<script>< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<script></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<script></S +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<script></SC +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<script></SCR +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<script></SCRI +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<script></SCRIP +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script></s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<script></sc +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<script></scr +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<script></scri +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<script></scrip +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script><! +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<script><!a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<script><!- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<script><!-a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<script><!-- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<script><!--< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<script><!--<a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<script><!--</ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--<s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<script><!--<script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<script><!--<script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<script><!--<script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<script><!--<script </s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<script><!--<script </scripta +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<script><!--<script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<script><!--<script </script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<script><!--<script </script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<script><!--<script </script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script - +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<script><!--<script -a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<script><!--<script -- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<script><!--<script --a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<script><!--<script --> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script -->< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<script><!--<script --></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script><\/script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<script><!--<script></scr'+'ipt>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<script><!--<script></script><script></script></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<script><!--<script></script><script></script>--><!--</script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<script><!--<script></script><script></script>-- ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<script><!--<script></script><script></script>- -></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<script><!--<script></script><script></script>- - ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<script><!--<script></script><script></script>-></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<script><!--<script>--!></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 44 Unexpected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 42 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<style><!--<style></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<style><!--</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<style><!--...</style>...--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 36 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<style><!--...</style><!-- --><style>@import ...</style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 48 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<style>...<!--[if IE]><style>...</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<title><!--<title>--> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (title). +#document +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<title></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noscript). +#document +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<noscript><!--</noscript>X<noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<noscript><iframe></noscript>X +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noframes). +#document +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<noframes><body><script><!--...</script></body></noframes></html> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +#document +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (textarea). +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<textarea></textarea></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +Line: 1 Col: 41 Unexpected end tag (iframe). +#document +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<iframe>...<!--X->...<!--/X->...</iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end tag (xmp). +#document +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE. +Line: 1 Col: 45 Unexpected end tag (noembed). +#document +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<!doctype html><table> + +#errors +Line 2 Col 0 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " +" + +#data +<!doctype html><table><td><span><font></span><span> +#errors +Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase. +Line 1 Col 45 Unexpected end tag (span). +Line 1 Col 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <span> +| <font> +| <font> +| <span> + +#data +<!doctype html><form><table></form><form></table></form> +#errors +35: Stray end tag “form”. +41: Start tag “form” seen in “table”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <table> +| <form> diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests17.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests17.dat new file mode 100644 index 00000000..7b555f88 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests17.dat @@ -0,0 +1,153 @@ +#data +<!doctype html><table><tbody><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tr><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<!doctype html><table><tr><td><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| <td> + +#data +<!doctype html><table><tr><th><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <th> +| <select> +| <td> + +#data +<!doctype html><table><caption><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <select> +| <tbody> +| <tr> + +#data +<!doctype html><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><th> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tbody> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><thead> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><caption> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><table><tr></table>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| "a" diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests18.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests18.dat new file mode 100644 index 00000000..680e1f06 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests18.dat @@ -0,0 +1,269 @@ +#data +<!doctype html><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> + +#data +<!doctype html><table><tbody><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><caption><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><tr><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <style> +| "</script>" + +#data +<!doctype html><table><tr><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <script> +| "</style>" + +#data +<!doctype html><table><caption><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><table><td><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" + +#data +<!doctype html><table><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> + +#data +<!doctype html><table><tr><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><frameset></frameset><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><frameset></frameset></html><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><table><tr></tbody><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <tfoot> + +#data +<!doctype html><table><td><svg></svg>abc<td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| "abc" +| <td> diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests19.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests19.dat new file mode 100644 index 00000000..0d62f5a5 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests19.dat @@ -0,0 +1,1237 @@ +#data +<!doctype html><math><mn DefinitionUrl="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| definitionURL="foo" + +#data +<!doctype html><html></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <!-- foo --> +| <head> +| <body> + +#data +<!doctype html><head></head></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- foo --> +| <body> + +#data +<!doctype html><body><p><pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <pre> + +#data +<!doctype html><body><p><listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <listing> + +#data +<!doctype html><p><plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <plaintext> + +#data +<!doctype html><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <h1> + +#data +<!doctype html><form><isindex> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> + +#data +<!doctype html><isindex action="POST"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| action="POST" +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex prompt="this is isindex"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "this is isindex" +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex type="hidden"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| type="hidden" +| <hr> + +#data +<!doctype html><isindex name="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><ruby><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rp> + +#data +<!doctype html><ruby><div><span><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rp> + +#data +<!doctype html><ruby><div><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rp> + +#data +<!doctype html><ruby><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rt> + +#data +<!doctype html><ruby><div><span><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rt> + +#data +<!doctype html><ruby><div><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rt> + +#data +<!doctype html><math/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <foo> + +#data +<!doctype html><svg/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <foo> + +#data +<!doctype html><div></body><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <!-- foo --> + +#data +<!doctype html><h1><div><h3><span></h1>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h1> +| <div> +| <h3> +| <span> +| "foo" + +#data +<!doctype html><p></h3>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "foo" + +#data +<!doctype html><h3><li>abc</h2>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h3> +| <li> +| "abc" +| "foo" + +#data +<!doctype html><table>abc<!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <!-- foo --> + +#data +<!doctype html><table> <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <!-- foo --> + +#data +<!doctype html><table> b <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " b " +| <table> +| <!-- foo --> + +#data +<!doctype html><select><option><option> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><p><math><mi><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mi> +| <p> +| <h1> + +#data +<!doctype html><p><math><mo><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mo> +| <p> +| <h1> + +#data +<!doctype html><p><math><mn><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <p> +| <h1> + +#data +<!doctype html><p><math><ms><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math ms> +| <p> +| <h1> + +#data +<!doctype html><p><math><mtext><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mtext> +| <p> +| <h1> + +#data +<!doctype html><frameset></noframes> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html c=d><body></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><html c=d><frameset></frameset></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <!-- foo --> + +#data +<!doctype html><html><frameset></frameset></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| " " + +#data +<!doctype html><html><frameset></frameset></html>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html></p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<html><frameset></frameset></html><!doctype html> +#errors +#document +| <html> +| <head> +| <frameset> + +#data +<!doctype html><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html><p><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><p>a<frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "a" + +#data +<!doctype html><p> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><pre><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> + +#data +<!doctype html><listing><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <listing> + +#data +<!doctype html><li><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <li> + +#data +<!doctype html><dd><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dd> + +#data +<!doctype html><dt><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> + +#data +<!doctype html><button><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <button> + +#data +<!doctype html><applet><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <applet> + +#data +<!doctype html><marquee><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <marquee> + +#data +<!doctype html><object><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> + +#data +<!doctype html><table><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> + +#data +<!doctype html><area><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <area> + +#data +<!doctype html><basefont><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <basefont> +| <frameset> + +#data +<!doctype html><bgsound><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <bgsound> +| <frameset> + +#data +<!doctype html><br><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <br> + +#data +<!doctype html><embed><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <embed> + +#data +<!doctype html><img><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html><input><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> + +#data +<!doctype html><keygen><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <keygen> + +#data +<!doctype html><wbr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <wbr> + +#data +<!doctype html><hr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <hr> + +#data +<!doctype html><textarea></textarea><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> + +#data +<!doctype html><xmp></xmp><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> + +#data +<!doctype html><iframe></iframe><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> + +#data +<!doctype html><select></select><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><svg></svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><math></math><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg><foreignObject><div> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg>a</svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| "a" + +#data +<!doctype html><svg> </svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<html>aaa<frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "aaa" + +#data +<html> a <frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "a " + +#data +<!doctype html><div><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><div><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> + +#data +<!doctype html><p><math></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| "a" + +#data +<!doctype html><p><math><mn><span></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <span> +| <p> +| "a" + +#data +<!doctype html><math></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!doctype html><meta charset="ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| charset="ascii" +| <body> + +#data +<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| content="text/html;charset=ascii" +| http-equiv="content-type" +| <body> + +#data +<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> +| <meta> +| charset="utf8" +| <body> + +#data +<!doctype html><html a=b><head></head><html c=d> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><image/> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html>a<i>b<table>c<b>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "a" +| <i> +| "bc" +| <b> +| "de" +| "f" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" + +#data +<!doctype html><table><i>a<b>b<div>c</i> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <i> +| "c" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><table><i>a<div>b<tr>c<b>d</i>e +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <div> +| "b" +| <i> +| "c" +| <b> +| "d" +| <b> +| "e" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><table><i>a<div>b<b>c</i>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <i> +| "a" +| <div> +| <i> +| "b" +| <b> +| "c" +| <b> +| "d" +| <table> + +#data +<!doctype html><body><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <bgsound> + +#data +<!doctype html><body><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <basefont> + +#data +<!doctype html><a><b></a><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <basefont> + +#data +<!doctype html><a><b></a><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <bgsound> + +#data +<!doctype html><figcaption><article></figcaption>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <figcaption> +| <article> +| "a" + +#data +<!doctype html><summary><article></summary>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <summary> +| <article> +| "a" + +#data +<!doctype html><p><a><plaintext>b +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <a> +| <plaintext> +| <a> +| "b" + +#data +<!DOCTYPE html><div>a<a></div>b<p>c</p>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| "a" +| <a> +| <a> +| "b" +| <p> +| "c" +| "d" diff --git a/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests2.dat b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests2.dat new file mode 100644 index 00000000..60d85922 --- /dev/null +++ b/vendor/github.com/documize/html-diff/vendor/golang.org/x/net/html/testdata/webkit/tests2.dat @@ -0,0 +1,763 @@ +#data +<!DOCTYPE html>Test +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Test" + +#data +<textarea>test</div>test +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 24 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <textarea> +| "test</div>test" + +#data +<table><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 11 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><td>test</tbody></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "test" + +#data +<frame>test +#errors +Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected start tag frame. Ignored. +#document +| <html> +| <head> +| <body> +| "test" + +#data +<!DOCTYPE html><frameset>test +#errors +Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset><!DOCTYPE html> +#errors +Line: 1 Col: 40 Unexpected DOCTYPE. Ignored. +Line: 1 Col: 40 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><font><p><b>test</font> +#errors +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <p> +| <font> +| <b> +| "test" + +#data +<!DOCTYPE html><dt><div><dd> +#errors +Line: 1 Col: 28 Missing end tag (div, dt). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> +| <div> +| <dd> + +#data +<script></x +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</x" +| <body> + +#data +<table><plaintext><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode. +Line: 1 Col: 22 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "<td>" +| <table> + +#data +<plaintext></plaintext> +#errors +Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!DOCTYPE html><table><tr>TEST +#errors +Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "TEST" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4> +#errors +Line: 1 Col: 37 Unexpected start tag (body). +Line: 1 Col: 53 Unexpected start tag (body). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| t1="1" +| t2="2" +| t3="3" +| t4="4" + +#data +</b test +#errors +Line: 1 Col: 8 Unexpected end of file in attribute name. +Line: 1 Col: 8 End tag contains unexpected attributes. +Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html></b test<b &=&>X +#errors +Line: 1 Col: 32 Named entity didn't end with ';'. +Line: 1 Col: 33 End tag contains unexpected attributes. +Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" + +#data +<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 54 Unexpected end of file in the tag name. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| type="text/x-foobar;baz" +| "X</SCRipt" +| <body> + +#data +& +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&# +#errors +Line: 1 Col: 1 Numeric entity expected. Got end of file instead. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#" + +#data +&#X +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#X" + +#data +&#x +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#x" + +#data +- +#errors +Line: 1 Col: 4 Numeric entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "-" + +#data +&x-test +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&x-test" + +#data +<!doctypehtml><p><li> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <li> + +#data +<!doctypehtml><p><dt> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dt> + +#data +<!doctypehtml><p><dd> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dd> + +#data +<!doctypehtml><p><form> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <form> + +#data +<!DOCTYPE html><p></P>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "X" + +#data +& +#errors +Line: 1 Col: 4 Named entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&AMp; +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&AMp;" + +#data +<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY> +#errors +Line: 1 Col: 110 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly> + +#data +<!DOCTYPE html>X</body>X +#errors +Line: 1 Col: 24 Unexpected non-space characters in the after body phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "XX" + +#data +<!DOCTYPE html><!-- X +#errors +Line: 1 Col: 21 Unexpected end of file in comment. +#document +| <!DOCTYPE html> +| <!-- X --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><table><caption>test TEST</caption><td>test +#errors +Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 58 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| "test TEST" +| <tbody> +| <tr> +| <td> +| "test" + +#data +<!DOCTYPE html><select><option><optgroup> +#errors +Line: 1 Col: 41 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option> +#errors +Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 76 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <option> +| <option> + +#data +<!DOCTYPE html><select><optgroup><option><optgroup> +#errors +Line: 1 Col: 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><datalist><option>foo</datalist>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <datalist> +| <option> +| "foo" +| "bar" + +#data +<!DOCTYPE html><font><input><input></font> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <input> +| <input> + +#data +<!DOCTYPE html><!-- XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX +#errors +Line: 1 Col: 29 Unexpected end of file in comment (-) +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<isindex test=x name=x> +#errors +Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected start tag isindex. Don't use it! +#document +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| test="x" +| <hr> + +#data +test +test +#errors +Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "test +test" + +#data +<!DOCTYPE html><body><title>test</body> +#errors +#document +| +| +| +| +| +| "test</body>" + +#data +<!DOCTYPE html><body><title>X +#errors +#document +| +| +| +| +| +| "X" +| <meta> +| name="z" +| <link> +| rel="foo" +| <style> +| " +x { content:"</style" } " + +#data +<!DOCTYPE html><select><optgroup></optgroup></select> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> + +#data + + +#errors +Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html> <html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><script> +</script> <title>x +#errors +#document +| +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +#document +| +| +| +| +| "x" +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (style). +#document +| +| +| --> x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +|

    +#errors +#document +| +| +| +| +| +| ddd +#errors +#document +| +| +| +#errors +#document +| +| +| +| +|
  • +| +| ", + "
  • Story graph is inspired by progamming interactive worlds with linear logic by Chris Martens although it doesn’t realize any of the specific principles she develops in that thesis.