~singpolyma/hereva-adventures

e619085168faefd3678dcc2b60fb3d08fc073fe0 โ€” Stephen Paul Weber 6 months ago
Initial commit, with scripts, license, and demo story
A  => COPYING +437 -0
@@ 1,437 @@
The world of Hereva was created by David Revoy and others, see:
https://www.peppercarrot.com/en/static8/wiki

This content is unofficial, and is not endorsed by the creators of Hereva or
the Pepper & Carrot comic.

Unless otherwise noted, content in this repository is available under the
following license:

Attribution-ShareAlike 4.0 International

=======================================================================

Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

     Considerations for licensors: Our public licenses are
     intended for use by those authorized to give the public
     permission to use material in ways otherwise restricted by
     copyright and certain other rights. Our licenses are
     irrevocable. Licensors should read and understand the terms
     and conditions of the license they choose before applying it.
     Licensors should also secure all rights necessary before
     applying our licenses so that the public can reuse the
     material as expected. Licensors should clearly mark any
     material not subject to the license. This includes other CC-
     licensed material, or material used under an exception or
     limitation to copyright. More considerations for licensors:
    wiki.creativecommons.org/Considerations_for_licensors

     Considerations for the public: By using one of our public
     licenses, a licensor grants the public permission to use the
     licensed material under specified terms and conditions. If
     the licensor's permission is not necessary for any reason--for
     example, because of any applicable exception or limitation to
     copyright--then that use is not regulated by the license. Our
     licenses grant only permissions under copyright and certain
     other rights that a licensor has authority to grant. Use of
     the licensed material may still be restricted for other
     reasons, including because others have copyright or other
     rights in the material. A licensor may make special requests,
     such as asking that all changes be marked or described.
     Although not required by our licenses, you are encouraged to
     respect those requests where reasonable. More considerations
     for the public:
    wiki.creativecommons.org/Considerations_for_licensees

=======================================================================

Creative Commons Attribution-ShareAlike 4.0 International Public
License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.


Section 1 -- Definitions.

  a. Adapted Material means material subject to Copyright and Similar
     Rights that is derived from or based upon the Licensed Material
     and in which the Licensed Material is translated, altered,
     arranged, transformed, or otherwise modified in a manner requiring
     permission under the Copyright and Similar Rights held by the
     Licensor. For purposes of this Public License, where the Licensed
     Material is a musical work, performance, or sound recording,
     Adapted Material is always produced where the Licensed Material is
     synched in timed relation with a moving image.

  b. Adapter's License means the license You apply to Your Copyright
     and Similar Rights in Your contributions to Adapted Material in
     accordance with the terms and conditions of this Public License.

  c. BY-SA Compatible License means a license listed at
     creativecommons.org/compatiblelicenses, approved by Creative
     Commons as essentially the equivalent of this Public License.

  d. Copyright and Similar Rights means copyright and/or similar rights
     closely related to copyright including, without limitation,
     performance, broadcast, sound recording, and Sui Generis Database
     Rights, without regard to how the rights are labeled or
     categorized. For purposes of this Public License, the rights
     specified in Section 2(b)(1)-(2) are not Copyright and Similar
     Rights.

  e. Effective Technological Measures means those measures that, in the
     absence of proper authority, may not be circumvented under laws
     fulfilling obligations under Article 11 of the WIPO Copyright
     Treaty adopted on December 20, 1996, and/or similar international
     agreements.

  f. Exceptions and Limitations means fair use, fair dealing, and/or
     any other exception or limitation to Copyright and Similar Rights
     that applies to Your use of the Licensed Material.

  g. License Elements means the license attributes listed in the name
     of a Creative Commons Public License. The License Elements of this
     Public License are Attribution and ShareAlike.

  h. Licensed Material means the artistic or literary work, database,
     or other material to which the Licensor applied this Public
     License.

  i. Licensed Rights means the rights granted to You subject to the
     terms and conditions of this Public License, which are limited to
     all Copyright and Similar Rights that apply to Your use of the
     Licensed Material and that the Licensor has authority to license.

  j. Licensor means the individual(s) or entity(ies) granting rights
     under this Public License.

  k. Share means to provide material to the public by any means or
     process that requires permission under the Licensed Rights, such
     as reproduction, public display, public performance, distribution,
     dissemination, communication, or importation, and to make material
     available to the public including in ways that members of the
     public may access the material from a place and at a time
     individually chosen by them.

  l. Sui Generis Database Rights means rights other than copyright
     resulting from Directive 96/9/EC of the European Parliament and of
     the Council of 11 March 1996 on the legal protection of databases,
     as amended and/or succeeded, as well as other essentially
     equivalent rights anywhere in the world.

  m. You means the individual or entity exercising the Licensed Rights
     under this Public License. Your has a corresponding meaning.


Section 2 -- Scope.

  a. License grant.

       1. Subject to the terms and conditions of this Public License,
          the Licensor hereby grants You a worldwide, royalty-free,
          non-sublicensable, non-exclusive, irrevocable license to
          exercise the Licensed Rights in the Licensed Material to:

            a. reproduce and Share the Licensed Material, in whole or
               in part; and

            b. produce, reproduce, and Share Adapted Material.

       2. Exceptions and Limitations. For the avoidance of doubt, where
          Exceptions and Limitations apply to Your use, this Public
          License does not apply, and You do not need to comply with
          its terms and conditions.

       3. Term. The term of this Public License is specified in Section
          6(a).

       4. Media and formats; technical modifications allowed. The
          Licensor authorizes You to exercise the Licensed Rights in
          all media and formats whether now known or hereafter created,
          and to make technical modifications necessary to do so. The
          Licensor waives and/or agrees not to assert any right or
          authority to forbid You from making technical modifications
          necessary to exercise the Licensed Rights, including
          technical modifications necessary to circumvent Effective
          Technological Measures. For purposes of this Public License,
          simply making modifications authorized by this Section 2(a)
          (4) never produces Adapted Material.

       5. Downstream recipients.

            a. Offer from the Licensor -- Licensed Material. Every
               recipient of the Licensed Material automatically
               receives an offer from the Licensor to exercise the
               Licensed Rights under the terms and conditions of this
               Public License.

            b. Additional offer from the Licensor -- Adapted Material.
               Every recipient of Adapted Material from You
               automatically receives an offer from the Licensor to
               exercise the Licensed Rights in the Adapted Material
               under the conditions of the Adapter's License You apply.

            c. No downstream restrictions. You may not offer or impose
               any additional or different terms or conditions on, or
               apply any Effective Technological Measures to, the
               Licensed Material if doing so restricts exercise of the
               Licensed Rights by any recipient of the Licensed
               Material.

       6. No endorsement. Nothing in this Public License constitutes or
          may be construed as permission to assert or imply that You
          are, or that Your use of the Licensed Material is, connected
          with, or sponsored, endorsed, or granted official status by,
          the Licensor or others designated to receive attribution as
          provided in Section 3(a)(1)(A)(i).

  b. Other rights.

       1. Moral rights, such as the right of integrity, are not
          licensed under this Public License, nor are publicity,
          privacy, and/or other similar personality rights; however, to
          the extent possible, the Licensor waives and/or agrees not to
          assert any such rights held by the Licensor to the limited
          extent necessary to allow You to exercise the Licensed
          Rights, but not otherwise.

       2. Patent and trademark rights are not licensed under this
          Public License.

       3. To the extent possible, the Licensor waives any right to
          collect royalties from You for the exercise of the Licensed
          Rights, whether directly or through a collecting society
          under any voluntary or waivable statutory or compulsory
          licensing scheme. In all other cases the Licensor expressly
          reserves any right to collect such royalties.


Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

  a. Attribution.

       1. If You Share the Licensed Material (including in modified
          form), You must:

            a. retain the following if it is supplied by the Licensor
               with the Licensed Material:

                 i. identification of the creator(s) of the Licensed
                    Material and any others designated to receive
                    attribution, in any reasonable manner requested by
                    the Licensor (including by pseudonym if
                    designated);

                ii. a copyright notice;

               iii. a notice that refers to this Public License;

                iv. a notice that refers to the disclaimer of
                    warranties;

                 v. a URI or hyperlink to the Licensed Material to the
                    extent reasonably practicable;

            b. indicate if You modified the Licensed Material and
               retain an indication of any previous modifications; and

            c. indicate the Licensed Material is licensed under this
               Public License, and include the text of, or the URI or
               hyperlink to, this Public License.

       2. You may satisfy the conditions in Section 3(a)(1) in any
          reasonable manner based on the medium, means, and context in
          which You Share the Licensed Material. For example, it may be
          reasonable to satisfy the conditions by providing a URI or
          hyperlink to a resource that includes the required
          information.

       3. If requested by the Licensor, You must remove any of the
          information required by Section 3(a)(1)(A) to the extent
          reasonably practicable.

  b. ShareAlike.

     In addition to the conditions in Section 3(a), if You Share
     Adapted Material You produce, the following conditions also apply.

       1. The Adapter's License You apply must be a Creative Commons
          license with the same License Elements, this version or
          later, or a BY-SA Compatible License.

       2. You must include the text of, or the URI or hyperlink to, the
          Adapter's License You apply. You may satisfy this condition
          in any reasonable manner based on the medium, means, and
          context in which You Share Adapted Material.

       3. You may not offer or impose any additional or different terms
          or conditions on, or apply any Effective Technological
          Measures to, Adapted Material that restrict exercise of the
          rights granted under the Adapter's License You apply.


Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
     to extract, reuse, reproduce, and Share all or a substantial
     portion of the contents of the database;

  b. if You include all or a substantial portion of the database
     contents in a database in which You have Sui Generis Database
     Rights, then the database in which You have Sui Generis Database
     Rights (but not its individual contents) is Adapted Material,

     including for purposes of Section 3(b); and
  c. You must comply with the conditions in Section 3(a) if You Share
     all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.


Section 5 -- Disclaimer of Warranties and Limitation of Liability.

  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

  c. The disclaimer of warranties and limitation of liability provided
     above shall be interpreted in a manner that, to the extent
     possible, most closely approximates an absolute disclaimer and
     waiver of all liability.


Section 6 -- Term and Termination.

  a. This Public License applies for the term of the Copyright and
     Similar Rights licensed here. However, if You fail to comply with
     this Public License, then Your rights under this Public License
     terminate automatically.

  b. Where Your right to use the Licensed Material has terminated under
     Section 6(a), it reinstates:

       1. automatically as of the date the violation is cured, provided
          it is cured within 30 days of Your discovery of the
          violation; or

       2. upon express reinstatement by the Licensor.

     For the avoidance of doubt, this Section 6(b) does not affect any
     right the Licensor may have to seek remedies for Your violations
     of this Public License.

  c. For the avoidance of doubt, the Licensor may also offer the
     Licensed Material under separate terms or conditions or stop
     distributing the Licensed Material at any time; however, doing so
     will not terminate this Public License.

  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
     License.


Section 7 -- Other Terms and Conditions.

  a. The Licensor shall not be bound by any additional or different
     terms or conditions communicated by You unless expressly agreed.

  b. Any arrangements, understandings, or agreements regarding the
     Licensed Material not stated herein are separate from and
     independent of the terms and conditions of this Public License.


Section 8 -- Interpretation.

  a. For the avoidance of doubt, this Public License does not, and
     shall not be interpreted to, reduce, limit, restrict, or impose
     conditions on any use of the Licensed Material that could lawfully
     be made without permission under this Public License.

  b. To the extent possible, if any provision of this Public License is
     deemed unenforceable, it shall be automatically reformed to the
     minimum extent necessary to make it enforceable. If the provision
     cannot be reformed, it shall be severed from this Public License
     without affecting the enforceability of the remaining terms and
     conditions.

  c. No term or condition of this Public License will be waived and no
     failure to comply consented to unless expressly agreed to by the
     Licensor.

  d. Nothing in this Public License constitutes or may be interpreted
     as a limitation upon, or waiver of, any privileges and immunities
     that apply to the Licensor or You, including from the legal
     processes of any jurisdiction or authority.


=======================================================================

Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the โ€œLicensor.โ€ The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.


A  => Hereva1/Cottage +6 -0
@@ 1,6 @@
:: [startnode]
You are in Pepper's cottage.

There is a chair<sup>(link-repeat: "๐Ÿ‘๏ธ")[(alert: "It's a rocking chair")]</sup> here.

You can [[go out the door->Woods]]

A  => Hereva1/Komonoa +1 -0
@@ 1,1 @@
This is Komonoa.

A  => Hereva1/Village +5 -0
@@ 1,5 @@
|akey>[{(unless: $inventory contains "key")[
There is a (link: "key")[(set: $inventory to it + (ds:"key"))(replace: ?akey)[]] here.
]}]

[[Go home->Cottage]]

A  => Hereva1/Woods +31 -0
@@ 1,31 @@
You are in the woods near Pepper's cottage.

A troll<sup>(link-repeat: "๐Ÿ‘๏ธ")[(alert: "Such an ugly troll")]</sup> asks where you are going.
|dialogue>[
(link: "To the village.")[
  (replace: ?dialogue)[
	To the village.
	
	He says you may [[go->Village]].
  ]
]

(link: "To the cottage.")[
  (replace: ?dialogue)[
	To the cottage.
	
	He says you may [[go->Cottage]].
  ]
]

(link: "To Komonoa.")[
  (replace: ?dialogue)[
	To Komonoa.
	
	(if: visits < 5)[He blocks your way.
	
	[[Goodbye.->Cottage]]
	](else:)[He says you may [[go->Komonoa]].]
  ]
]
]

A  => Hereva1/footer +5 -0
@@ 1,5 @@
:: [footer]
(live:0.5s)[(if: $inventory's length > 0)[
----
Inventory: $inventory
]]

A  => Hereva1/startup +2 -0
@@ 1,2 @@
:: [startup]
(set: $inventory to (ds:))

A  => Makefile +9 -0
@@ 1,9 @@
build/Hereva1/index.html: build/vendor dist-head.html Hereva1/*
	mkdir -p build/Hereva1
	cat dist-head.html > build/Hereva1/index.html
	bin/twine-assemble 898CE5C1-2E9D-4294-9E04-F20EBAA5B1A3 Hereva1/* >> build/Hereva1/index.html
	echo "</body></html>" >> build/Hereva1/index.html

build/vendor: vendor/*
	mkdir -p build
	cp -r vendor build/

A  => bin/twine-assemble +56 -0
@@ 1,56 @@
#!/bin/sh
# This program is free software: you can redistribute it and/or modify
# under the terms of the GNU Affero General Public License as
# by the Free Software Foundation, either version 3 of the
# , or (at your option) any later version.
#
# program is distributed in the hope that it will be useful,
# WITHOUT ANY WARRANTY; without even the implied warranty of
# or FITNESS FOR A PARTICULAR PURPOSE.  See the
# Affero General Public License for more details.
#
# should have received a copy of the GNU Affero General Public License
# with this program.  If not, see <https://www.gnu.org/licenses/>.

IFID="$1"

if ! [ "$(printf "%s" "$IFID" | wc -c)" = 36 ]; then
	echo "First argument must be a valid IFID." 1>&2
	echo "You can use this one:" 1>&2
	uuidgen | tr '[a-f]' '[A-F]' 1>&2
	exit 1
fi

shift

printf '<tw-storydata ifid="%s" startnode="1" creator="twine-cli" creator-version="0.1.0" format="Harlowe" format-version="3.1.0" hidden>\n' "$IFID"

id="2"
while [ $# -gt 0 ]; do

	cat="cat"

	if tags="$(head -n1 "$1" | grep -o '^:: \[.*\]$')"; then
		tags="$(printf "%s\n" "$tags" | cut -d'[' -f2 | cut -d']' -f1)"
		cat="tail -n+2"
	fi

	if printf "%s\n" "$tags" | grep "startnode" > /dev/null; then
		oldid="$id"
		id="1"
	fi

	printf '<tw-passagedata pid="%d" name="%s" tags="%s">\n' "$id" "$(basename "$1" .txt)" "$tags"
	$cat "$1" | sed -e's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g;'
	echo '</tw-passagedata>'
	echo

	if printf "%s\n" "$tags" | grep "startnode" > /dev/null; then
		id="$oldid"
	fi

	shift
	id="$(( $id + 1 ))"
done

echo '</tw-storydata>'

A  => build/Hereva1/index.html +80 -0
@@ 1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="../vendor/harlowe-dist.css">
<script type="text/javascript" src="../vendor/harlowe-dist.js"></script>
</head>

<body>

<tw-story><noscript><tw-noscript>JavaScript needs to be enabled to play.</tw-noscript></noscript></tw-story>

<tw-storydata ifid="898CE5C1-2E9D-4294-9E04-F20EBAA5B1A3" startnode="1" creator="twine-cli" creator-version="0.1.0" format="Harlowe" format-version="3.1.0" hidden>
<tw-passagedata pid="1" name="Cottage" tags="startnode">
You are in Pepper's cottage.

There is a chair&lt;sup&gt;(link-repeat: "๐Ÿ‘๏ธ")[(alert: "It's a rocking chair")]&lt;/sup&gt; here.

You can [[go out the door-&gt;Woods]]
</tw-passagedata>

<tw-passagedata pid="3" name="Komonoa" tags="">
This is Komonoa.
</tw-passagedata>

<tw-passagedata pid="4" name="Village" tags="">
|akey&gt;[{(unless: $inventory contains "key")[
There is a (link: "key")[(set: $inventory to it + (ds:"key"))(replace: ?akey)[]] here.
]}]

[[Go home-&gt;Cottage]]
</tw-passagedata>

<tw-passagedata pid="5" name="Woods" tags="">
You are in the woods near Pepper's cottage.

A troll&lt;sup&gt;(link-repeat: "๐Ÿ‘๏ธ")[(alert: "Such an ugly troll")]&lt;/sup&gt; asks where you are going.
|dialogue&gt;[
(link: "To the village.")[
  (replace: ?dialogue)[
	To the village.
	
	He says you may [[go-&gt;Village]].
  ]
]

(link: "To the cottage.")[
  (replace: ?dialogue)[
	To the cottage.
	
	He says you may [[go-&gt;Cottage]].
  ]
]

(link: "To Komonoa.")[
  (replace: ?dialogue)[
	To Komonoa.
	
	(if: visits &lt; 5)[He blocks your way.
	
	[[Goodbye.-&gt;Cottage]]
	](else:)[He says you may [[go-&gt;Komonoa]].]
  ]
]
]
</tw-passagedata>

<tw-passagedata pid="6" name="footer" tags="footer">
(live:0.5s)[(if: $inventory's length &gt; 0)[
----
Inventory: $inventory
]]
</tw-passagedata>

<tw-passagedata pid="7" name="startup" tags="startup">
(set: $inventory to (ds:))
</tw-passagedata>

</tw-storydata>
</body></html>

A  => build/vendor/README +23 -0
@@ 1,23 @@
CSS and JS built from https://bitbucket.org/_L_/harlowe/ + dependencies.

Upstream license:

Copyright (c) 2019 Leon Arnott

This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.

Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an
acknowledgment in the product documentation would be appreciated but is not
required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.

A  => build/vendor/harlowe-dist.css +1409 -0
@@ 1,1409 @@
/*** Animations ***/
/* The following are used for (text-style:)s only */
@-webkit-keyframes appear {
  0% {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes appear {
  0% {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@-webkit-keyframes fade-in-out {
  0%, to {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@keyframes fade-in-out {
  0%, to {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@-webkit-keyframes rumble {
  0%, to {
  }
  50% {
    -webkit-transform: translateY(-0.2em);
    transform: translateY(-0.2em);
  }
}

@keyframes rumble {
  0%, to {
  }
  50% {
    -webkit-transform: translateY(-0.2em);
    transform: translateY(-0.2em);
  }
}

@-webkit-keyframes shudder {
  0%, to {
  }
  50% {
    -webkit-transform: translateX(0.2em);
    transform: translateX(0.2em);
  }
}

@keyframes shudder {
  0%, to {
  }
  50% {
    -webkit-transform: translateX(0.2em);
    transform: translateX(0.2em);
  }
}

/* The following are used for (transition:)s only */
@-webkit-keyframes box-flash {
  0% {
    background-color: white;
    color: white;
  }
  to {
  }
}

@keyframes box-flash {
  0% {
    background-color: white;
    color: white;
  }
  to {
  }
}

@-webkit-keyframes pulse {
  0% {
    -webkit-transform: scale(0, 0);
    transform: scale(0, 0);
  }
  20% {
    -webkit-transform: scale(1.2, 1.2);
    transform: scale(1.2, 1.2);
  }
  40% {
    -webkit-transform: scale(0.9, 0.9);
    transform: scale(0.9, 0.9);
  }
  60% {
    -webkit-transform: scale(1.05, 1.05);
    transform: scale(1.05, 1.05);
  }
  80% {
    -webkit-transform: scale(0.925, 0.925);
    transform: scale(0.925, 0.925);
  }
  to {
    -webkit-transform: scale(1, 1);
    transform: scale(1, 1);
  }
}

@keyframes pulse {
  0% {
    -webkit-transform: scale(0, 0);
    transform: scale(0, 0);
  }
  20% {
    -webkit-transform: scale(1.2, 1.2);
    transform: scale(1.2, 1.2);
  }
  40% {
    -webkit-transform: scale(0.9, 0.9);
    transform: scale(0.9, 0.9);
  }
  60% {
    -webkit-transform: scale(1.05, 1.05);
    transform: scale(1.05, 1.05);
  }
  80% {
    -webkit-transform: scale(0.925, 0.925);
    transform: scale(0.925, 0.925);
  }
  to {
    -webkit-transform: scale(1, 1);
    transform: scale(1, 1);
  }
}

@-webkit-keyframes shudder-in {
  0%, to {
    -webkit-transform: translateX(0em);
    transform: translateX(0em);
  }
  5%, 25%, 45% {
    -webkit-transform: translateX(-1em);
    transform: translateX(-1em);
  }
  15%, 35%, 55% {
    -webkit-transform: translateX(1em);
    transform: translateX(1em);
  }
  65% {
    -webkit-transform: translateX(-0.6em);
    transform: translateX(-0.6em);
  }
  75% {
    -webkit-transform: translateX(0.6em);
    transform: translateX(0.6em);
  }
  85% {
    -webkit-transform: translateX(-0.2em);
    transform: translateX(-0.2em);
  }
  95% {
    -webkit-transform: translateX(0.2em);
    transform: translateX(0.2em);
  }
}

@keyframes shudder-in {
  0%, to {
    -webkit-transform: translateX(0em);
    transform: translateX(0em);
  }
  5%, 25%, 45% {
    -webkit-transform: translateX(-1em);
    transform: translateX(-1em);
  }
  15%, 35%, 55% {
    -webkit-transform: translateX(1em);
    transform: translateX(1em);
  }
  65% {
    -webkit-transform: translateX(-0.6em);
    transform: translateX(-0.6em);
  }
  75% {
    -webkit-transform: translateX(0.6em);
    transform: translateX(0.6em);
  }
  85% {
    -webkit-transform: translateX(-0.2em);
    transform: translateX(-0.2em);
  }
  95% {
    -webkit-transform: translateX(0.2em);
    transform: translateX(0.2em);
  }
}

@-webkit-keyframes rumble-in {
  0%, to {
    -webkit-transform: translateY(0em);
    transform: translateY(0em);
  }
  5%, 25%, 45% {
    -webkit-transform: translateY(-1em);
    transform: translateY(-1em);
  }
  15%, 35%, 55% {
    -webkit-transform: translateY(1em);
    transform: translateY(1em);
  }
  65% {
    -webkit-transform: translateY(-0.6em);
    transform: translateY(-0.6em);
  }
  75% {
    -webkit-transform: translateY(0.6em);
    transform: translateY(0.6em);
  }
  85% {
    -webkit-transform: translateY(-0.2em);
    transform: translateY(-0.2em);
  }
  95% {
    -webkit-transform: translateY(0.2em);
    transform: translateY(0.2em);
  }
}

@keyframes rumble-in {
  0%, to {
    -webkit-transform: translateY(0em);
    transform: translateY(0em);
  }
  5%, 25%, 45% {
    -webkit-transform: translateY(-1em);
    transform: translateY(-1em);
  }
  15%, 35%, 55% {
    -webkit-transform: translateY(1em);
    transform: translateY(1em);
  }
  65% {
    -webkit-transform: translateY(-0.6em);
    transform: translateY(-0.6em);
  }
  75% {
    -webkit-transform: translateY(0.6em);
    transform: translateY(0.6em);
  }
  85% {
    -webkit-transform: translateY(-0.2em);
    transform: translateY(-0.2em);
  }
  95% {
    -webkit-transform: translateY(0.2em);
    transform: translateY(0.2em);
  }
}

@-webkit-keyframes slide-right {
  0% {
    -webkit-transform: translateX(-100vw);
    transform: translateX(-100vw);
  }
  to {
  }
}

@keyframes slide-right {
  0% {
    -webkit-transform: translateX(-100vw);
    transform: translateX(-100vw);
  }
  to {
  }
}

@-webkit-keyframes slide-left {
  0% {
    -webkit-transform: translateX(100vw);
    transform: translateX(100vw);
  }
  to {
  }
}

@keyframes slide-left {
  0% {
    -webkit-transform: translateX(100vw);
    transform: translateX(100vw);
  }
  to {
  }
}

@-webkit-keyframes slide-up {
  0% {
    -webkit-transform: translateY(100vh);
    transform: translateY(100vh);
  }
  to {
  }
}

@keyframes slide-up {
  0% {
    -webkit-transform: translateY(100vh);
    transform: translateY(100vh);
  }
  to {
  }
}

@-webkit-keyframes slide-down {
  0% {
    -webkit-transform: translateY(-100vh);
    transform: translateY(-100vh);
  }
  to {
  }
}

@keyframes slide-down {
  0% {
    -webkit-transform: translateY(-100vh);
    transform: translateY(-100vh);
  }
  to {
  }
}

@-webkit-keyframes flicker {
  0%, 29%, 31%, 63%, 65%, 77%, 79%, 86%, 88%, 91%, 93% {
    opacity: 0;
  }
  30% {
    opacity: 0.2;
  }
  64% {
    opacity: 0.4;
  }
  78% {
    opacity: 0.6;
  }
  87% {
    opacity: 0.8;
  }
  92%, to {
    opacity: 1;
  }
}

@keyframes flicker {
  0%, 29%, 31%, 63%, 65%, 77%, 79%, 86%, 88%, 91%, 93% {
    opacity: 0;
  }
  30% {
    opacity: 0.2;
  }
  64% {
    opacity: 0.4;
  }
  78% {
    opacity: 0.6;
  }
  87% {
    opacity: 0.8;
  }
  92%, to {
    opacity: 1;
  }
}

/*** Debug mode ***/
.debug-mode {
  /* Colours for other things */
  /* Show destinations of links */
}

.debug-mode tw-expression[type=hookref] {
  background-color: rgba(115, 123, 140, 0.15);
  /* Show the IDs of hooks */
}

.debug-mode tw-expression[type=hookref]::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "?" attr(name);
}

.debug-mode tw-expression[type=variable] {
  background-color: rgba(140, 128, 115, 0.15);
}

.debug-mode tw-expression[type=variable]::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "$" attr(name);
}

.debug-mode tw-expression[type=tempVariable] {
  background-color: rgba(140, 128, 115, 0.15);
}

.debug-mode tw-expression[type=tempVariable]::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "_" attr(name);
}

.debug-mode tw-expression[type=macro] {
  /* Colours for generic macros */
  /* Colours for specific macros */
  /* Show the macro call */
}

.debug-mode tw-expression[type=macro]:nth-of-type(4n+0) {
  background-color: rgba(136, 153, 102, 0.15);
}

.debug-mode tw-expression[type=macro]:nth-of-type(2n+1) {
  background-color: rgba(102, 153, 102, 0.15);
}

.debug-mode tw-expression[type=macro]:nth-of-type(4n+2) {
  background-color: rgba(102, 153, 136, 0.15);
}

.debug-mode tw-expression[type=macro][name="for"], .debug-mode tw-expression[type=macro][name="loop"], .debug-mode tw-expression[type=macro][name="print"], .debug-mode tw-expression[type=macro][name="enchant"], .debug-mode tw-expression[type=macro][name="display"] {
  background-color: rgba(0, 170, 255, 0.1) !important;
}

.debug-mode tw-expression[type=macro][name="if"], .debug-mode tw-expression[type=macro][name="unless"], .debug-mode tw-expression[type=macro][name="elseif"], .debug-mode tw-expression[type=macro][name="else"] {
  /* (if:), (elseif:), (else:) and (unless:) have special hook colouring. */
}

.debug-mode tw-expression[type=macro][name="if"], .debug-mode tw-expression[type=macro][name="if"] + tw-hook:not([name]), .debug-mode tw-expression[type=macro][name="unless"], .debug-mode tw-expression[type=macro][name="unless"] + tw-hook:not([name]), .debug-mode tw-expression[type=macro][name="elseif"], .debug-mode tw-expression[type=macro][name="elseif"] + tw-hook:not([name]), .debug-mode tw-expression[type=macro][name="else"], .debug-mode tw-expression[type=macro][name="else"] + tw-hook:not([name]) {
  background-color: rgba(0, 255, 0, 0.1) !important;
}

.debug-mode tw-expression[type=macro][name="hidden"], .debug-mode tw-expression[type=macro].false {
  background-color: rgba(255, 0, 0, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name="hidden"] + tw-hook:not([name]), .debug-mode tw-expression[type=macro].false + tw-hook:not([name]) {
  display: none;
}

.debug-mode tw-expression[type=macro][name="either"], .debug-mode tw-expression[type=macro][name="a"], .debug-mode tw-expression[type=macro][name="dm"], .debug-mode tw-expression[type=macro][name="ds"], .debug-mode tw-expression[type=macro][name="array"], .debug-mode tw-expression[type=macro][name^="sub"], .debug-mode tw-expression[type=macro][name="altered"], .debug-mode tw-expression[type=macro][name="count"], .debug-mode tw-expression[type=macro][name^="data"], .debug-mode tw-expression[type=macro][name="find"], .debug-mode tw-expression[type=macro][name$="ed"], .debug-mode tw-expression[type=macro][name$="-pass"], .debug-mode tw-expression[type=macro][name="range"], .debug-mode tw-expression[type=macro][name^="num"], .debug-mode tw-expression[type=macro][name^="str"], .debug-mode tw-expression[type=macro][name="text"], .debug-mode tw-expression[type=macro][name^="lower"], .debug-mode tw-expression[type=macro][name^="upper"], .debug-mode tw-expression[type=macro][name="words"], .debug-mode tw-expression[type=macro][name="ceil"], .debug-mode tw-expression[type=macro][name="floor"], .debug-mode tw-expression[type=macro][name="random"], .debug-mode tw-expression[type=macro][name="abs"], .debug-mode tw-expression[type=macro][name="cos"], .debug-mode tw-expression[type=macro][name="exp"], .debug-mode tw-expression[type=macro][name^="log"], .debug-mode tw-expression[type=macro][name="max"], .debug-mode tw-expression[type=macro][name="min"], .debug-mode tw-expression[type=macro][name="pow"], .debug-mode tw-expression[type=macro][name="sign"], .debug-mode tw-expression[type=macro][name="sin"], .debug-mode tw-expression[type=macro][name="sqrt"], .debug-mode tw-expression[type=macro][name="tan"], .debug-mode tw-expression[type=macro][name="round"], .debug-mode tw-expression[type=macro][name^="hsl"], .debug-mode tw-expression[type=macro][name^="rgb"] {
  background-color: rgba(255, 255, 0, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name$="-game"], .debug-mode tw-expression[type=macro][name="move"], .debug-mode tw-expression[type=macro][name="put"], .debug-mode tw-expression[type=macro][name="set"] {
  background-color: rgba(255, 128, 0, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name^="link"], .debug-mode tw-expression[type=macro][name$="-link"], .debug-mode tw-expression[type=macro][name="dropdown"], .debug-mode tw-expression[type=macro][name^="click"], .debug-mode tw-expression[type=macro][name="goto"], .debug-mode tw-expression[type=macro][name="undo"], .debug-mode tw-expression[type=macro][name^="mouseo"] {
  background-color: rgba(32, 191, 223, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name^="replace"], .debug-mode tw-expression[type=macro][name^="prepend"], .debug-mode tw-expression[type=macro][name^="append"], .debug-mode tw-expression[type=macro][name="show"], .debug-mode tw-expression[type=macro][name^="remove"] {
  background-color: rgba(223, 96, 32, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name="event"], .debug-mode tw-expression[type=macro][name="live"] {
  background-color: rgba(32, 32, 223, 0.2) !important;
}

.debug-mode tw-expression[type=macro][name="align"], .debug-mode tw-expression[type=macro][name^="colo"], .debug-mode tw-expression[type=macro][name="background"], .debug-mode tw-expression[type=macro][name="css"], .debug-mode tw-expression[type=macro][name="font"], .debug-mode tw-expression[type=macro][name="hook"], .debug-mode tw-expression[type=macro][name$="-style"], .debug-mode tw-expression[type=macro][name^="text-"], .debug-mode tw-expression[type=macro][name^="transition"], .debug-mode tw-expression[type=macro][name^="t8n"], .debug-mode tw-expression[type=macro][name="live"] {
  background-color: rgba(255, 191, 0, 0.2) !important;
}

.debug-mode tw-expression[type=macro]::before {
  content: "(" attr(name) ":)";
  padding: 0 0.5rem;
  font-size: 1rem;
  vertical-align: middle;
  line-height: normal;
  background-color: inherit;
  border: 1px solid rgba(255, 255, 255, 0.5);
}

.debug-mode tw-hook {
  background-color: rgba(0, 85, 255, 0.1) !important;
  /*
			Show the hook syntax. This should line up with what Harlowe expects.
			
			But, of course, anonymous hooks shouldn't be highlighted like this.
		*/
}

.debug-mode tw-hook::before {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "[";
}

.debug-mode tw-hook::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "]";
}

.debug-mode tw-hook[name] {
  /* Show the IDs of named hooks */
}

.debug-mode tw-hook[name]::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "]<" attr(name) "|";
}

.debug-mode tw-pseudo-hook {
  background-color: rgba(255, 170, 0, 0.1) !important;
}

.debug-mode tw-collapsed::before {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "{";
}

.debug-mode tw-collapsed::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "}";
}

.debug-mode tw-verbatim::before, .debug-mode tw-verbatim::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: "`";
}

.debug-mode tw-align[style*="text-align: center"] {
  background: linear-gradient(to right, rgba(255, 204, 189, 0) 0%, rgba(255, 204, 189, 0.25) 50%, rgba(255, 204, 189, 0) 100%);
}

.debug-mode tw-align[style*="text-align: left"] {
  background: linear-gradient(to right, rgba(255, 204, 189, 0.25) 0%, rgba(255, 204, 189, 0) 100%);
}

.debug-mode tw-align[style*="text-align: right"] {
  background: linear-gradient(to right, rgba(255, 204, 189, 0) 0%, rgba(255, 204, 189, 0.25) 100%);
}

.debug-mode tw-column {
  background-color: rgba(189, 228, 255, 0.2);
}

.debug-mode tw-enchantment {
  animation: enchantment 0.5s infinite;
  -webkit-animation: enchantment 0.5s infinite;
  border: 1px solid;
}

.debug-mode tw-link::after,
.debug-mode tw-broken-link::after {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: attr(passage-name);
}

.debug-mode tw-include {
  background-color: rgba(204, 128, 51, 0.1);
}

.debug-mode tw-include::before {
  font-size: 0.8rem;
  padding-left: 0.2rem;
  padding-right: 0.2rem;
  vertical-align: top;
  content: attr(type) ' "' attr(title) '"';
}

@keyframes enchantment {
  0%, to {
    border-color: #ffb366;
  }
  50% {
    border-color: #66ffcc;
  }
}

@-webkit-keyframes enchantment {
  0%, to {
    border-color: #ffb366;
  }
  50% {
    border-color: #66ffcc;
  }
}

tw-debugger {
  position: fixed;
  box-sizing: border-box;
  bottom: 0;
  right: 0;
  z-index: 999999;
  min-width: 10em;
  min-height: 1em;
  padding: 0em 1em 1em 1em;
  font-size: 1.25em;
  font-family: sans-serif;
  color: black;
  border-left: solid #000 2px;
  border-top: solid #000 2px;
  border-top-left-radius: 0.5em;
  background: white;
  opacity: 1;
}

tw-debugger select {
  margin-right: 1em;
  width: 12em;
}

tw-debugger button {
  border-radius: 3px;
  border: solid #999 1px;
  margin: auto 4px;
  background-color: #fff;
  font-size: inherit;
  color: black;
}

tw-debugger button.enabled {
  background-color: #eee;
  box-shadow: inset #ddd 3px 5px 0.5em;
}

tw-debugger .panel {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-direction: normal;
  -webkit-box-orient: vertical;
  -webkit-flex-direction: column;
  -moz-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  position: absolute;
  bottom: 100%;
  left: -2px;
  right: 0;
  padding: 1em;
  max-height: 40vh;
  overflow-y: scroll;
  overflow-x: hidden;
  z-index: 999998;
  background: white;
  border: inherit;
  border-bottom: solid #999 2px;
  border-top-left-radius: 0.5em;
  border-bottom-left-radius: 0.5em;
  font-size: 0.8em;
}

tw-debugger .panel:empty, tw-debugger .panel[hidden] {
  display: none;
}

tw-debugger .panel table {
  border-spacing: 0px;
}

tw-debugger .variable-row {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-direction: normal;
  -webkit-box-orient: horizontal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  flex-shrink: 0;
}

tw-debugger .variable-row:nth-child(2n) {
  background: #EEE;
}

tw-debugger .variable-row .variable-name, tw-debugger .variable-row .variable-value {
  display: inline-block;
  width: 50%;
}

tw-debugger .variable-row .variable-path {
  opacity: 0.4;
}

tw-debugger .variable-row .temporary-variable-scope {
  opacity: 0.8;
  font-size: 0.75em;
}

tw-debugger .variable-row .temporary-variable-scope::before {
  content: " in ";
}

tw-debugger .variable-row .global::before {
  content: "$";
}

tw-debugger .variable-row .temporary::before {
  content: "_";
}

tw-debugger .error-row {
  background-color: rgba(230, 101, 204, 0.3);
}

tw-debugger .error-row:nth-child(2n) {
  background-color: rgba(237, 145, 219, 0.3);
}

tw-debugger .error-row * {
  padding: 0.25em 0.5em;
}

tw-debugger .error-row .error-message {
  cursor: help;
}

tw-debugger .storylet-row {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-direction: normal;
  -webkit-box-orient: horizontal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  flex-shrink: 0;
  background-color: rgba(201, 233, 222, 0.3);
}

tw-debugger .storylet-row:nth-child(2n) {
  background-color: rgba(128, 203, 178, 0.3);
}

tw-debugger .storylet-row.storylet-closed {
  font-style: italic;
  opacity: 0.4;
  background-color: rgba(217, 217, 217, 0.3);
}

tw-debugger .storylet-row.storylet-closed:nth-child(2n) {
  background-color: rgba(166, 166, 166, 0.3);
}

tw-debugger .storylet-row.storylet-error {
  background-color: rgba(230, 101, 204, 0.3);
}

tw-debugger .storylet-row.storylet-error:nth-child(2n) {
  background-color: rgba(237, 145, 219, 0.3);
}

tw-debugger .storylet-row .storylet-name, tw-debugger .storylet-row .storylet-value {
  display: inline-block;
  width: 50%;
}

tw-debugger .panel-source {
  font-family: monospace;
  overflow-x: scroll;
  white-space: pre;
}

tw-debugger .tabs {
  padding-bottom: 0.5em;
}

tw-debugger .tab {
  border-radius: 0px 0px 0.5em 0.5em;
  border-top: none;
}

tw-dialog {
  z-index: 999997;
  position: fixed;
  left: auto;
  right: auto;
  bottom: auto;
  top: auto;
  border: white solid 2px;
  padding: 2em;
  color: white;
  background-color: black;
  display: block;
  max-width: 50vw;
  max-height: 75vh;
  overflow: hidden;
}

tw-dialog input[type=text] {
  font-size: inherit;
  width: 100%;
}

tw-backdrop {
  z-index: 999996;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
}

tw-link, .link, tw-icon, .enchantment-clickblock {
  cursor: pointer;
}

tw-link, .enchantment-link {
  color: #4169E1;
  font-weight: bold;
  text-decoration: none;
  transition: color 0.2s ease-in-out;
}

tw-passage tw-enchantment[style^="color"] tw-link:not(:hover),
tw-passage tw-enchantment[style*=" color"] tw-link:not(:hover), tw-passage tw-enchantment[style^="color"] .enchantment-link:not(:hover),
tw-passage tw-enchantment[style*=" color"] .enchantment-link:not(:hover) {
  color: inherit;
}

tw-link:hover, .enchantment-link:hover {
  color: DeepSkyBlue;
}

tw-link:active, .enchantment-link:active {
  color: #DD4B39;
}

.visited {
  color: #6941e1;
}

tw-passage tw-enchantment[style^="color"] .visited:not(:hover),
tw-passage tw-enchantment[style*=" color"] .visited:not(:hover) {
  color: inherit;
}

.visited:hover {
  color: #E3E;
}

tw-broken-link {
  color: #993333;
  border-bottom: 2px solid #993333;
  cursor: not-allowed;
}

tw-passage tw-enchantment[style^="color"] tw-broken-link:not(:hover),
tw-passage tw-enchantment[style*=" color"] tw-broken-link:not(:hover) {
  color: inherit;
}

.enchantment-mouseover {
  border-bottom: 1px dashed #999;
}

.enchantment-mouseoverblock {
  border: 1px dashed #999;
  display: block;
}

.enchantment-mouseout, .enchantment-mouseoutblock {
  border: rgba(64, 149, 191, 0.6) 1px solid;
}

.enchantment-mouseout:hover, .enchantment-mouseoutblock:hover {
  background-color: rgba(64, 149, 191, 0.25);
  border: transparent 1px solid;
  border-radius: 0.2em;
}

.enchantment-mouseout .enchantment-mouseoutblock, .enchantment-mouseoutblock .enchantment-mouseoutblock {
  display: block;
}

.enchantment-clickblock {
  width: 100%;
  height: 100%;
  display: block;
}

.enchantment-clickblock::after {
  content: "";
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  display: block;
  position: absolute;
  pointer-events: none;
  box-shadow: 0 0 0 0.5vmax;
  color: rgba(65, 105, 225, 0.5);
  transition: color 0.2s ease-in-out;
}

.enchantment-clickblock:hover::after {
  color: rgba(0, 191, 255, 0.5);
}

.enchantment-clickblock:active::after {
  color: rgba(222, 78, 59, 0.5);
}

body > .enchantment-clickblock::after {
  box-shadow: inset 0 0 0 0.5vmax;
}

/*** Styling elements, for general use by Twine authors ***/
h1 {
  font-size: 3em;
}

h2 {
  font-size: 2.25em;
}

h3 {
  font-size: 1.75em;
}

h1, h2, h3, h4, h5, h6 {
  line-height: 1em;
  margin: 0.3em 0 0.6em 0;
}

pre {
  font-size: 1rem;
  /* This overrides the normal line-height of <tw-story>. */
  line-height: initial;
}

small {
  font-size: 70%;
}

big {
  font-size: 120%;
}

mark {
  color: rgba(0, 0, 0, 0.6);
  background-color: #ff9;
}

ins {
  color: rgba(0, 0, 0, 0.6);
  background-color: rgba(255, 242, 204, 0.5);
  /* Yellowed correction fluid */
  border-radius: 0.5em;
  box-shadow: 0em 0em 0.2em #ffe699;
  text-decoration: none;
}

/* Who am I to tell authors not to use non-standard tags? */
center {
  text-align: center;
  margin: 0 auto;
  width: 60%;
}

blink {
  text-decoration: none;
  animation: fade-in-out 1s steps(1, end) infinite alternate;
  -webkit-animation: fade-in-out 1s steps(1, end) infinite alternate;
}

/*** Secondary text styles, used by certain markup structures ***/
tw-align {
  display: block;
}

tw-columns {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-direction: normal;
  -webkit-box-orient: horizontal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  -webkit-justify-content: space-between;
  -moz-justify-content: space-between;
  justify-content: space-between;
}

/* Transitions */
/* Invalid/instant transition */
.transition-in {
  -webkit-animation: appear 0ms step-start;
  animation: appear 0ms step-start;
}

.transition-out {
  -webkit-animation: appear 0ms step-end;
  animation: appear 0ms step-end;
}

/* Dissolve */
[data-t8n^=dissolve].transition-in {
  -webkit-animation: appear 0.8s;
  animation: appear 0.8s;
}

[data-t8n^=dissolve].transition-out {
  -webkit-animation: appear 0.8s reverse;
  animation: appear 0.8s reverse;
}

/* Shudder */
[data-t8n^=shudder].transition-in {
  display: inline-block;
  -webkit-animation: shudder-in 0.8s;
  animation: shudder-in 0.8s;
}

[data-t8n^=shudder].transition-out {
  display: inline-block;
  -webkit-animation: shudder-in 0.8s reverse;
  animation: shudder-in 0.8s reverse;
}

/* Rumble */
[data-t8n^=rumble].transition-in {
  display: inline-block;
  -webkit-animation: rumble-in 0.8s;
  animation: rumble-in 0.8s;
}

[data-t8n^=rumble].transition-out {
  display: inline-block;
  -webkit-animation: rumble-in 0.8s reverse;
  animation: rumble-in 0.8s reverse;
}

/* Box-flash */
[data-t8n^=boxflash].transition-in {
  -webkit-animation: box-flash 0.8s;
  animation: box-flash 0.8s;
}

/* Pulse */
[data-t8n^=pulse].transition-in {
  -webkit-animation: pulse 0.8s;
  animation: pulse 0.8s;
  display: inline-block;
}

[data-t8n^=pulse].transition-out {
  -webkit-animation: pulse 0.8s reverse;
  animation: pulse 0.8s reverse;
  display: inline-block;
}

/* Slide */
/*
	These can't have the hyphen in their data-t8n name because Utils.insensitiveName() removes it.
	Also, the transition-outs use the reverse direction of the transition-ins to preserve the semantic
	meaning of the names.
*/
[data-t8n^=slideleft].transition-in {
  -webkit-animation: slide-left 0.8s;
  animation: slide-left 0.8s;
  display: inline-block;
}

[data-t8n^=slideleft].transition-out {
  -webkit-animation: slide-right 0.8s reverse;
  animation: slide-right 0.8s reverse;
  display: inline-block;
}

[data-t8n^=slideright].transition-in {
  -webkit-animation: slide-right 0.8s;
  animation: slide-right 0.8s;
  display: inline-block;
}

[data-t8n^=slideright].transition-out {
  -webkit-animation: slide-left 0.8s reverse;
  animation: slide-left 0.8s reverse;
  display: inline-block;
}

[data-t8n^=slideup].transition-in {
  -webkit-animation: slide-up 0.8s;
  animation: slide-up 0.8s;
  display: inline-block;
}

[data-t8n^=slideup].transition-out {
  -webkit-animation: slide-down 0.8s reverse;
  animation: slide-down 0.8s reverse;
  display: inline-block;
}

[data-t8n^=slidedown].transition-in {
  -webkit-animation: slide-down 0.8s;
  animation: slide-down 0.8s;
  display: inline-block;
}

[data-t8n^=slidedown].transition-out {
  -webkit-animation: slide-up 0.8s reverse;
  animation: slide-up 0.8s reverse;
  display: inline-block;
}

/* Flicker */
[data-t8n^=flicker].transition-in {
  -webkit-animation: flicker 0.8s;
  animation: flicker 0.8s;
}

[data-t8n^=flicker].transition-out {
  -webkit-animation: flicker 0.8s reverse;
  animation: flicker 0.8s reverse;
}

/* Modifiers */
[data-t8n$=fast] {
  animation-duration: 0.4s;
  -webkit-animation-duration: 0.4s;
}

/* Modifiers */
[data-t8n$=slow] {
  animation-duration: 1.6s;
  -webkit-animation-duration: 1.6s;
}

/*
	<html> should be left alone, except where needed to accomodate <tw-story>.
*/
html {
  margin: 0;
  height: 100%;
  overflow-x: hidden;
}

/*
	This enables border-box on every element by default, unless overridden
	by a parent element.
	It also enables position:relative by default, which allows top, left, etc.
	to be used heedlessly.
*/
*, :before, :after {
  position: relative;
  box-sizing: inherit;
}

body {
  margin: 0;
  height: 100%;
}

/*
	<tw-storydata> houses the raw passage data of the story.
	Of course, it can't be visible.
*/
tw-storydata {
  display: none;
}

/*
	The <tw-story> element houses all of the <tw-passage>s.
	This element can be styled by setting a ChangerCommand to ?page
*/
tw-story {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-direction: normal;
  -webkit-box-orient: vertical;
  -webkit-flex-direction: column;
  -moz-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  font: 100% Georgia, serif;
  box-sizing: border-box;
  /*
		Instead of a 60% width, this uses 40% horizontal padding (applied below).
	*/
  width: 100%;
  min-height: 100%;
  /*
		This is the base font size, which is permuted below.
	*/
  font-size: 1.5em;
  line-height: 1.5em;
  /*
		The <tw-story>'s default distance from the top and bottom of the page is 5%.
	*/
  padding: 5% 20%;
  /*
		This is necessary to make certain CSS animations (mainly slide-left) work with passages.
	*/
  overflow: hidden;
  background-color: black;
  color: white;
  /*
		This causes consecutive line breaks to consume less height than they normally would.
		The [data-cons] attr is installed by Renderer. To keep the CSS class namespace empty for authors,
		it's a custom attr and not a class.
	*/
  /*
		These are created by (dropdown:).
		This selector should be more specific, but I'm concerned about it being harder for user stylesheets
		to override... so I'm leaving it as-is.
	*/
  /*
		This animation for the <noscript> element should ideally prevent a "flash of unstyled content" where the
		message is briefly visible.
	*/
}

tw-story br[data-cons] {
  display: block;
  height: 0;
  margin: 0.8ex 0;
}

tw-story select {
  background-color: transparent;
  font: inherit;
  border-style: solid;
  padding: 2px;
}

tw-story select:not([disabled]) {
  color: inherit;
}

tw-story tw-noscript {
  animation: appear 0.8s;
  -webkit-animation: appear 0.8s;
}

/*
	The <tw-passage> element houses a single passage, including its sidebar.
*/
tw-passage {
  display: block;
}

/*
	The <tw-sidebar> is the first element in a <tw-passage>, and is placed to the left
	when the story begins.
*/
tw-sidebar {
  left: -5em;
  width: 3em;
  position: absolute;
  text-align: center;
  display: block;
}

/*
	A <tw-icon> is, at present, a sidebar button.
*/
tw-icon {
  display: block;
  margin: 0.5em 0;
  opacity: 0.2;
  font-size: 2.75em;
}

tw-icon:hover {
  opacity: 0.4;
}

/*** Inner passage formatting ***/
/*
	These are the primary clickable game elements:
	<tw-link>  : passage links
	.link      : enchantment links
	tw-icon    : the undo button
*/
tw-hook:empty, tw-expression:empty {
  display: none;
}

tw-error {
  display: inline-block;
  border-radius: 0.2em;
  padding: 0.2em;
  font-size: 1rem;
  cursor: help;
  white-space: pre-wrap;
}

tw-error.error {
  background-color: rgba(223, 58, 190, 0.4);
  color: white;
}

tw-error.warning {
  background-color: rgba(223, 140, 58, 0.4);
  color: white;
  display: none;
}

.debug-mode tw-error.warning {
  display: inline;
}

tw-error-explanation {
  display: block;
  font-size: 0.8rem;
  line-height: 1rem;
}

tw-error-explanation-button {
  cursor: pointer;
  line-height: 0em;
  border-radius: 1px;
  border: 1px solid black;
  font-size: 0.8rem;
  margin: 0 0.4rem;
  opacity: 0.5;
}

tw-error-explanation-button .folddown-arrowhead {
  display: inline-block;
}

tw-notifier {
  border-radius: 0.2em;
  padding: 0.2em;
  font-size: 1rem;
  background-color: rgba(223, 182, 58, 0.4);
  display: none;
}

.debug-mode tw-notifier {
  display: inline;
}

tw-notifier::before {
  content: attr(message);
}

/*
	When a Colour type is printed, it comes out as a <tw-colour> element.
*/
tw-colour {
  border: 1px solid black;
  display: inline-block;
  width: 1em;
  height: 1em;
}

A  => build/vendor/harlowe-dist.js +34042 -0
@@ 1,34042 @@
'use strict';

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

(function () {
	/**
  * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
  * Released under MIT license, http://github.com/requirejs/almond/LICENSE
  */
	//Going sloppy to avoid 'use strict' string cost, but strict practices should
	//be followed.
	/*global setTimeout: false */

	var requirejs, require, define;
	(function (undef) {
		var main,
		    _req,
		    makeMap,
		    handlers,
		    defined = {},
		    waiting = {},
		    config = {},
		    defining = {},
		    hasOwn = Object.prototype.hasOwnProperty,
		    aps = [].slice,
		    jsSuffixRegExp = /\.js$/;

		function hasProp(obj, prop) {
			return hasOwn.call(obj, prop);
		}

		/**
   * Given a relative module name, like ./something, normalize it to
   * a real name that can be mapped to a path.
   * @param {String} name the relative name
   * @param {String} baseName a real name that the name arg is relative
   * to.
   * @returns {String} normalized name
   */
		function normalize(name, baseName) {
			var nameParts,
			    nameSegment,
			    mapValue,
			    foundMap,
			    lastIndex,
			    foundI,
			    foundStarMap,
			    starI,
			    i,
			    j,
			    part,
			    normalizedBaseParts,
			    baseParts = baseName && baseName.split("/"),
			    map = config.map,
			    starMap = map && map['*'] || {};

			//Adjust any relative paths.
			if (name) {
				name = name.split('/');
				lastIndex = name.length - 1;

				// If wanting node ID compatibility, strip .js from end
				// of IDs. Have to do this here, and not in nameToUrl
				// because node allows either .js or non .js to map
				// to same file.
				if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
					name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
				}

				// Starts with a '.' so need the baseName
				if (name[0].charAt(0) === '.' && baseParts) {
					//Convert baseName to array, and lop off the last part,
					//so that . matches that 'directory' and not name of the baseName's
					//module. For instance, baseName of 'one/two/three', maps to
					//'one/two/three.js', but we want the directory, 'one/two' for
					//this normalization.
					normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
					name = normalizedBaseParts.concat(name);
				}

				//start trimDots
				for (i = 0; i < name.length; i++) {
					part = name[i];
					if (part === '.') {
						name.splice(i, 1);
						i -= 1;
					} else if (part === '..') {
						// If at the start, or previous value is still ..,
						// keep them so that when converted to a path it may
						// still work when converted to a path, even though
						// as an ID it is less than ideal. In larger point
						// releases, may be better to just kick out an error.
						if (i === 0 || i === 1 && name[2] === '..' || name[i - 1] === '..') {
							continue;
						} else if (i > 0) {
							name.splice(i - 1, 2);
							i -= 2;
						}
					}
				}
				//end trimDots

				name = name.join('/');
			}

			//Apply map config if available.
			if ((baseParts || starMap) && map) {
				nameParts = name.split('/');

				for (i = nameParts.length; i > 0; i -= 1) {
					nameSegment = nameParts.slice(0, i).join("/");

					if (baseParts) {
						//Find the longest baseName segment match in the config.
						//So, do joins on the biggest to smallest lengths of baseParts.
						for (j = baseParts.length; j > 0; j -= 1) {
							mapValue = map[baseParts.slice(0, j).join('/')];

							//baseName segment has  config, find if it has one for
							//this name.
							if (mapValue) {
								mapValue = mapValue[nameSegment];
								if (mapValue) {
									//Match, update name to the new value.
									foundMap = mapValue;
									foundI = i;
									break;
								}
							}
						}
					}

					if (foundMap) {
						break;
					}

					//Check for a star map match, but just hold on to it,
					//if there is a shorter segment match later in a matching
					//config, then favor over this star map.
					if (!foundStarMap && starMap && starMap[nameSegment]) {
						foundStarMap = starMap[nameSegment];
						starI = i;
					}
				}

				if (!foundMap && foundStarMap) {
					foundMap = foundStarMap;
					foundI = starI;
				}

				if (foundMap) {
					nameParts.splice(0, foundI, foundMap);
					name = nameParts.join('/');
				}
			}

			return name;
		}

		function makeRequire(relName, forceSync) {
			return function () {
				//A version of a require function that passes a moduleName
				//value for items that may need to
				//look up paths relative to the moduleName
				var args = aps.call(arguments, 0);

				//If first arg is not require('string'), and there is only
				//one arg, it is the array form without a callback. Insert
				//a null so that the following concat is correct.
				if (typeof args[0] !== 'string' && args.length === 1) {
					args.push(null);
				}
				return _req.apply(undef, args.concat([relName, forceSync]));
			};
		}

		function makeNormalize(relName) {
			return function (name) {
				return normalize(name, relName);
			};
		}

		function makeLoad(depName) {
			return function (value) {
				defined[depName] = value;
			};
		}

		function callDep(name) {
			if (hasProp(waiting, name)) {
				var args = waiting[name];
				delete waiting[name];
				defining[name] = true;
				main.apply(undef, args);
			}

			if (!hasProp(defined, name) && !hasProp(defining, name)) {
				throw new Error('No ' + name);
			}
			return defined[name];
		}

		//Turns a plugin!resource to [plugin, resource]
		//with the plugin being undefined if the name
		//did not have a plugin prefix.
		function splitPrefix(name) {
			var prefix,
			    index = name ? name.indexOf('!') : -1;
			if (index > -1) {
				prefix = name.substring(0, index);
				name = name.substring(index + 1, name.length);
			}
			return [prefix, name];
		}

		//Creates a parts array for a relName where first part is plugin ID,
		//second part is resource ID. Assumes relName has already been normalized.
		function makeRelParts(relName) {
			return relName ? splitPrefix(relName) : [];
		}

		/**
   * Makes a name map, normalizing the name, and using a plugin
   * for normalization if necessary. Grabs a ref to plugin
   * too, as an optimization.
   */
		makeMap = function makeMap(name, relParts) {
			var plugin,
			    parts = splitPrefix(name),
			    prefix = parts[0],
			    relResourceName = relParts[1];

			name = parts[1];

			if (prefix) {
				prefix = normalize(prefix, relResourceName);
				plugin = callDep(prefix);
			}

			//Normalize according
			if (prefix) {
				if (plugin && plugin.normalize) {
					name = plugin.normalize(name, makeNormalize(relResourceName));
				} else {
					name = normalize(name, relResourceName);
				}
			} else {
				name = normalize(name, relResourceName);
				parts = splitPrefix(name);
				prefix = parts[0];
				name = parts[1];
				if (prefix) {
					plugin = callDep(prefix);
				}
			}

			//Using ridiculous property names for space reasons
			return {
				f: prefix ? prefix + '!' + name : name, //fullName
				n: name,
				pr: prefix,
				p: plugin
			};
		};

		function makeConfig(name) {
			return function () {
				return config && config.config && config.config[name] || {};
			};
		}

		handlers = {
			require: function require(name) {
				return makeRequire(name);
			},
			exports: function exports(name) {
				var e = defined[name];
				if (typeof e !== 'undefined') {
					return e;
				} else {
					return defined[name] = {};
				}
			},
			module: function module(name) {
				return {
					id: name,
					uri: '',
					exports: defined[name],
					config: makeConfig(name)
				};
			}
		};

		main = function main(name, deps, callback, relName) {
			var cjsModule,
			    depName,
			    ret,
			    map,
			    i,
			    relParts,
			    args = [],
			    callbackType = typeof callback === 'undefined' ? 'undefined' : _typeof(callback),
			    usingExports;

			//Use name if no relName
			relName = relName || name;
			relParts = makeRelParts(relName);

			//Call the callback to define the module, if necessary.
			if (callbackType === 'undefined' || callbackType === 'function') {
				//Pull out the defined dependencies and pass the ordered
				//values to the callback.
				//Default to [require, exports, module] if no deps
				deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
				for (i = 0; i < deps.length; i += 1) {
					map = makeMap(deps[i], relParts);
					depName = map.f;

					//Fast path CommonJS standard dependencies.
					if (depName === "require") {
						args[i] = handlers.require(name);
					} else if (depName === "exports") {
						//CommonJS module spec 1.1
						args[i] = handlers.exports(name);
						usingExports = true;
					} else if (depName === "module") {
						//CommonJS module spec 1.1
						cjsModule = args[i] = handlers.module(name);
					} else if (hasProp(defined, depName) || hasProp(waiting, depName) || hasProp(defining, depName)) {
						args[i] = callDep(depName);
					} else if (map.p) {
						map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
						args[i] = defined[depName];
					} else {
						throw new Error(name + ' missing ' + depName);
					}
				}

				ret = callback ? callback.apply(defined[name], args) : undefined;

				if (name) {
					//If setting exports via "module" is in play,
					//favor that over return value and exports. After that,
					//favor a non-undefined return value over exports use.
					if (cjsModule && cjsModule.exports !== undef && cjsModule.exports !== defined[name]) {
						defined[name] = cjsModule.exports;
					} else if (ret !== undef || !usingExports) {
						//Use the return value from the function.
						defined[name] = ret;
					}
				}
			} else if (name) {
				//May just be an object definition for the module. Only
				//worry about defining if have a module name.
				defined[name] = callback;
			}
		};

		requirejs = require = _req = function req(deps, callback, relName, forceSync, alt) {
			if (typeof deps === "string") {
				if (handlers[deps]) {
					//callback in this case is really relName
					return handlers[deps](callback);
				}
				//Just return the module wanted. In this scenario, the
				//deps arg is the module name, and second arg (if passed)
				//is just the relName.
				//Normalize module name, if it contains . or ..
				return callDep(makeMap(deps, makeRelParts(callback)).f);
			} else if (!deps.splice) {
				//deps is a config object, not an array.
				config = deps;
				if (config.deps) {
					_req(config.deps, config.callback);
				}
				if (!callback) {
					return;
				}

				if (callback.splice) {
					//callback is an array, which means it is a dependency list.
					//Adjust args if there are dependencies
					deps = callback;
					callback = relName;
					relName = null;
				} else {
					deps = undef;
				}
			}

			//Support require(['a'])
			callback = callback || function () {};

			//If relName is a function, it is an errback handler,
			//so remove it.
			if (typeof relName === 'function') {
				relName = forceSync;
				forceSync = alt;
			}

			//Simulate async callback;
			if (forceSync) {
				main(undef, deps, callback, relName);
			} else {
				//Using a non-zero value because of concern for what old browsers
				//do, and latest browsers "upgrade" to 4 if lower value is used:
				//http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
				//If want a value immediately, use require('id') instead -- something
				//that works in almond on the global level, but not guaranteed and
				//unlikely to work in other AMD implementations.
				setTimeout(function () {
					main(undef, deps, callback, relName);
				}, 4);
			}

			return _req;
		};

		/**
   * Just drops the config on the floor, but returns req in case
   * the config return value is used.
   */
		_req.config = function (cfg) {
			return _req(cfg);
		};

		/**
   * Expose module registry for debugging and tooling
   */
		requirejs._defined = defined;

		define = function define(name, deps, callback) {
			if (typeof name !== 'string') {
				throw new Error('See almond README: incorrect module build, no module name');
			}

			//This module may not have dependencies
			if (!deps.splice) {
				//deps is not an array, so probably means
				//an object literal or factory function for
				//the value. Adjust args.
				callback = deps;
				deps = [];
			}

			if (!hasProp(defined, name) && !hasProp(waiting, name)) {
				waiting[name] = [name, deps, callback];
			}
		};

		define.amd = {
			jQuery: true
		};
	})();

	define("almond", function () {});

	/*!
  * jQuery JavaScript Library v3.4.1
  * https://jquery.com/
  *
  * Includes Sizzle.js
  * https://sizzlejs.com/
  *
  * Copyright JS Foundation and other contributors
  * Released under the MIT license
  * https://jquery.org/license
  *
  * Date: 2019-05-01T21:04Z
  */
	(function (global, factory) {

		"use strict";

		if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === "object" && _typeof(module.exports) === "object") {

			// For CommonJS and CommonJS-like environments where a proper `window`
			// is present, execute the factory and get jQuery.
			// For environments that do not have a `window` with a `document`
			// (such as Node.js), expose a factory as module.exports.
			// This accentuates the need for the creation of a real `window`.
			// e.g. var jQuery = require("jquery")(window);
			// See ticket #14549 for more info.
			module.exports = global.document ? factory(global, true) : function (w) {
				if (!w.document) {
					throw new Error("jQuery requires a window with a document");
				}
				return factory(w);
			};
		} else {
			factory(global);
		}

		// Pass this if window is not defined yet
	})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {

		// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
		// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
		// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
		// enough that all such attempts are guarded in a try block.
		"use strict";

		var arr = [];

		var document = window.document;

		var getProto = Object.getPrototypeOf;

		var _slice = arr.slice;

		var concat = arr.concat;

		var push = arr.push;

		var indexOf = arr.indexOf;

		var class2type = {};

		var toString = class2type.toString;

		var hasOwn = class2type.hasOwnProperty;

		var fnToString = hasOwn.toString;

		var ObjectFunctionString = fnToString.call(Object);

		var support = {};

		var isFunction = function isFunction(obj) {

			// Support: Chrome <=57, Firefox <=52
			// In some browsers, typeof returns "function" for HTML <object> elements
			// (i.e., `typeof document.createElement( "object" ) === "function"`).
			// We don't want to classify *any* DOM node as a function.
			return typeof obj === "function" && typeof obj.nodeType !== "number";
		};

		var isWindow = function isWindow(obj) {
			return obj != null && obj === obj.window;
		};

		var preservedScriptAttributes = {
			type: true,
			src: true,
			nonce: true,
			noModule: true
		};

		function DOMEval(code, node, doc) {
			doc = doc || document;

			var i,
			    val,
			    script = doc.createElement("script");

			script.text = code;
			if (node) {
				for (i in preservedScriptAttributes) {

					// Support: Firefox 64+, Edge 18+
					// Some browsers don't support the "nonce" property on scripts.
					// On the other hand, just using `getAttribute` is not enough as
					// the `nonce` attribute is reset to an empty string whenever it
					// becomes browsing-context connected.
					// See https://github.com/whatwg/html/issues/2369
					// See https://html.spec.whatwg.org/#nonce-attributes
					// The `node.getAttribute` check was added for the sake of
					// `jQuery.globalEval` so that it can fake a nonce-containing node
					// via an object.
					val = node[i] || node.getAttribute && node.getAttribute(i);
					if (val) {
						script.setAttribute(i, val);
					}
				}
			}
			doc.head.appendChild(script).parentNode.removeChild(script);
		}

		function toType(obj) {
			if (obj == null) {
				return obj + "";
			}

			// Support: Android <=2.3 only (functionish RegExp)
			return (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
		}
		/* global Symbol */
		// Defining this global in .eslintrc.json would create a danger of using the global
		// unguarded in another place, it seems safer to define global only for this module


		var version = "3.4.1",


		// Define a local copy of jQuery
		jQuery = function jQuery(selector, context) {

			// The jQuery object is actually just the init constructor 'enhanced'
			// Need init if jQuery is called (just allow error to be thrown if not included)
			return new jQuery.fn.init(selector, context);
		},


		// Support: Android <=4.0 only
		// Make sure we trim BOM and NBSP
		rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

		jQuery.fn = jQuery.prototype = {

			// The current version of jQuery being used
			jquery: version,

			constructor: jQuery,

			// The default length of a jQuery object is 0
			length: 0,

			toArray: function toArray() {
				return _slice.call(this);
			},

			// Get the Nth element in the matched element set OR
			// Get the whole matched element set as a clean array
			get: function get(num) {

				// Return all the elements in a clean array
				if (num == null) {
					return _slice.call(this);
				}

				// Return just the one element from the set
				return num < 0 ? this[num + this.length] : this[num];
			},

			// Take an array of elements and push it onto the stack
			// (returning the new matched element set)
			pushStack: function pushStack(elems) {

				// Build a new jQuery matched element set
				var ret = jQuery.merge(this.constructor(), elems);

				// Add the old object onto the stack (as a reference)
				ret.prevObject = this;

				// Return the newly-formed element set
				return ret;
			},

			// Execute a callback for every element in the matched set.
			each: function each(callback) {
				return jQuery.each(this, callback);
			},

			map: function map(callback) {
				return this.pushStack(jQuery.map(this, function (elem, i) {
					return callback.call(elem, i, elem);
				}));
			},

			slice: function slice() {
				return this.pushStack(_slice.apply(this, arguments));
			},

			first: function first() {
				return this.eq(0);
			},

			last: function last() {
				return this.eq(-1);
			},

			eq: function eq(i) {
				var len = this.length,
				    j = +i + (i < 0 ? len : 0);
				return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
			},

			end: function end() {
				return this.prevObject || this.constructor();
			},

			// For internal use only.
			// Behaves like an Array's method, not like a jQuery method.
			push: push,
			sort: arr.sort,
			splice: arr.splice
		};

		jQuery.extend = jQuery.fn.extend = function () {
			var options,
			    name,
			    src,
			    copy,
			    copyIsArray,
			    clone,
			    target = arguments[0] || {},
			    i = 1,
			    length = arguments.length,
			    deep = false;

			// Handle a deep copy situation
			if (typeof target === "boolean") {
				deep = target;

				// Skip the boolean and the target
				target = arguments[i] || {};
				i++;
			}

			// Handle case when target is a string or something (possible in deep copy)
			if ((typeof target === 'undefined' ? 'undefined' : _typeof(target)) !== "object" && !isFunction(target)) {
				target = {};
			}

			// Extend jQuery itself if only one argument is passed
			if (i === length) {
				target = this;
				i--;
			}

			for (; i < length; i++) {

				// Only deal with non-null/undefined values
				if ((options = arguments[i]) != null) {

					// Extend the base object
					for (name in options) {
						copy = options[name];

						// Prevent Object.prototype pollution
						// Prevent never-ending loop
						if (name === "__proto__" || target === copy) {
							continue;
						}

						// Recurse if we're merging plain objects or arrays
						if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
							src = target[name];

							// Ensure proper type for the source value
							if (copyIsArray && !Array.isArray(src)) {
								clone = [];
							} else if (!copyIsArray && !jQuery.isPlainObject(src)) {
								clone = {};
							} else {
								clone = src;
							}
							copyIsArray = false;

							// Never move original objects, clone them
							target[name] = jQuery.extend(deep, clone, copy);

							// Don't bring in undefined values
						} else if (copy !== undefined) {
							target[name] = copy;
						}
					}
				}
			}

			// Return the modified object
			return target;
		};

		jQuery.extend({

			// Unique for each copy of jQuery on the page
			expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),

			// Assume jQuery is ready without the ready module
			isReady: true,

			error: function error(msg) {
				throw new Error(msg);
			},

			noop: function noop() {},

			isPlainObject: function isPlainObject(obj) {
				var proto, Ctor;

				// Detect obvious negatives
				// Use toString instead of jQuery.type to catch host objects
				if (!obj || toString.call(obj) !== "[object Object]") {
					return false;
				}

				proto = getProto(obj);

				// Objects with no prototype (e.g., `Object.create( null )`) are plain
				if (!proto) {
					return true;
				}

				// Objects with prototype are plain iff they were constructed by a global Object function
				Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
				return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
			},

			isEmptyObject: function isEmptyObject(obj) {
				var name;

				for (name in obj) {
					return false;
				}
				return true;
			},

			// Evaluates a script in a global context
			globalEval: function globalEval(code, options) {
				DOMEval(code, { nonce: options && options.nonce });
			},

			each: function each(obj, callback) {
				var length,
				    i = 0;

				if (isArrayLike(obj)) {
					length = obj.length;
					for (; i < length; i++) {
						if (callback.call(obj[i], i, obj[i]) === false) {
							break;
						}
					}
				} else {
					for (i in obj) {
						if (callback.call(obj[i], i, obj[i]) === false) {
							break;
						}
					}
				}

				return obj;
			},

			// Support: Android <=4.0 only
			trim: function trim(text) {
				return text == null ? "" : (text + "").replace(rtrim, "");
			},

			// results is for internal usage only
			makeArray: function makeArray(arr, results) {
				var ret = results || [];

				if (arr != null) {
					if (isArrayLike(Object(arr))) {
						jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
					} else {
						push.call(ret, arr);
					}
				}

				return ret;
			},

			inArray: function inArray(elem, arr, i) {
				return arr == null ? -1 : indexOf.call(arr, elem, i);
			},

			// Support: Android <=4.0 only, PhantomJS 1 only
			// push.apply(_, arraylike) throws on ancient WebKit
			merge: function merge(first, second) {
				var len = +second.length,
				    j = 0,
				    i = first.length;

				for (; j < len; j++) {
					first[i++] = second[j];
				}

				first.length = i;

				return first;
			},

			grep: function grep(elems, callback, invert) {
				var callbackInverse,
				    matches = [],
				    i = 0,
				    length = elems.length,
				    callbackExpect = !invert;

				// Go through the array, only saving the items
				// that pass the validator function
				for (; i < length; i++) {
					callbackInverse = !callback(elems[i], i);
					if (callbackInverse !== callbackExpect) {
						matches.push(elems[i]);
					}
				}

				return matches;
			},

			// arg is for internal usage only
			map: function map(elems, callback, arg) {
				var length,
				    value,
				    i = 0,
				    ret = [];

				// Go through the array, translating each of the items to their new values
				if (isArrayLike(elems)) {
					length = elems.length;
					for (; i < length; i++) {
						value = callback(elems[i], i, arg);

						if (value != null) {
							ret.push(value);
						}
					}

					// Go through every key on the object,
				} else {
					for (i in elems) {
						value = callback(elems[i], i, arg);

						if (value != null) {
							ret.push(value);
						}
					}
				}

				// Flatten any nested arrays
				return concat.apply([], ret);
			},

			// A global GUID counter for objects
			guid: 1,

			// jQuery.support is not used in Core but other projects attach their
			// properties to it so it needs to exist.
			support: support
		});

		if (typeof Symbol === "function") {
			jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
		}

		// Populate the class2type map
		jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function (i, name) {
			class2type["[object " + name + "]"] = name.toLowerCase();
		});

		function isArrayLike(obj) {

			// Support: real iOS 8.2 only (not reproducible in simulator)
			// `in` check used to prevent JIT error (gh-2145)
			// hasOwn isn't used here due to false negatives
			// regarding Nodelist length in IE
			var length = !!obj && "length" in obj && obj.length,
			    type = toType(obj);

			if (isFunction(obj) || isWindow(obj)) {
				return false;
			}

			return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
		}
		var Sizzle =
		/*!
   * Sizzle CSS Selector Engine v2.3.4
   * https://sizzlejs.com/
   *
   * Copyright JS Foundation and other contributors
   * Released under the MIT license
   * https://js.foundation/
   *
   * Date: 2019-04-08
   */
		function (window) {

			var i,
			    support,
			    Expr,
			    getText,
			    isXML,
			    tokenize,
			    compile,
			    select,
			    outermostContext,
			    sortInput,
			    hasDuplicate,


			// Local document vars
			setDocument,
			    document,
			    docElem,
			    documentIsHTML,
			    rbuggyQSA,
			    rbuggyMatches,
			    matches,
			    contains,


			// Instance-specific data
			expando = "sizzle" + 1 * new Date(),
			    preferredDoc = window.document,
			    dirruns = 0,
			    done = 0,
			    classCache = createCache(),
			    tokenCache = createCache(),
			    compilerCache = createCache(),
			    nonnativeSelectorCache = createCache(),
			    sortOrder = function sortOrder(a, b) {
				if (a === b) {
					hasDuplicate = true;
				}
				return 0;
			},


			// Instance methods
			hasOwn = {}.hasOwnProperty,
			    arr = [],
			    pop = arr.pop,
			    push_native = arr.push,
			    push = arr.push,
			    slice = arr.slice,

			// Use a stripped-down indexOf as it's faster than native
			// https://jsperf.com/thor-indexof-vs-for/5
			indexOf = function indexOf(list, elem) {
				var i = 0,
				    len = list.length;
				for (; i < len; i++) {
					if (list[i] === elem) {
						return i;
					}
				}
				return -1;
			},
			    booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",


			// Regular expressions

			// http://www.w3.org/TR/css3-selectors/#whitespace
			whitespace = "[\\x20\\t\\r\\n\\f]",


			// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
			identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",


			// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
			attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
			// Operator (capture 2)
			"*([*^$|!~]?=)" + whitespace +
			// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
			"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]",
			    pseudos = ":(" + identifier + ")(?:\\((" +
			// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
			// 1. quoted (capture 3; capture 4 or capture 5)
			"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
			// 2. simple (capture 6)
			"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
			// 3. anything else (capture 2)
			".*" + ")\\)|)",


			// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
			rwhitespace = new RegExp(whitespace + "+", "g"),
			    rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),
			    rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),
			    rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"),
			    rdescend = new RegExp(whitespace + "|>"),
			    rpseudo = new RegExp(pseudos),
			    ridentifier = new RegExp("^" + identifier + "$"),
			    matchExpr = {
				"ID": new RegExp("^#(" + identifier + ")"),
				"CLASS": new RegExp("^\\.(" + identifier + ")"),
				"TAG": new RegExp("^(" + identifier + "|[*])"),
				"ATTR": new RegExp("^" + attributes),
				"PSEUDO": new RegExp("^" + pseudos),
				"CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
				"bool": new RegExp("^(?:" + booleans + ")$", "i"),
				// For use in libraries implementing .is()
				// We use this for POS matching in `select`
				"needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
			},
			    rhtml = /HTML$/i,
			    rinputs = /^(?:input|select|textarea|button)$/i,
			    rheader = /^h\d$/i,
			    rnative = /^[^{]+\{\s*\[native \w/,


			// Easily-parseable/retrievable ID or TAG or CLASS selectors
			rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
			    rsibling = /[+~]/,


			// CSS escapes
			// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
			runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),
			    funescape = function funescape(_, escaped, escapedWhitespace) {
				var high = "0x" + escaped - 0x10000;
				// NaN means non-codepoint
				// Support: Firefox<24
				// Workaround erroneous numeric interpretation of +"0x"
				return high !== high || escapedWhitespace ? escaped : high < 0 ?
				// BMP codepoint
				String.fromCharCode(high + 0x10000) :
				// Supplemental Plane codepoint (surrogate pair)
				String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
			},


			// CSS string/identifier serialization
			// https://drafts.csswg.org/cssom/#common-serializing-idioms
			rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
			    fcssescape = function fcssescape(ch, asCodePoint) {
				if (asCodePoint) {

					// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
					if (ch === "\0") {
						return '\uFFFD';
					}

					// Control characters and (dependent upon position) numbers get escaped as code points
					return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
				}

				// Other potentially-special ASCII characters get backslash-escaped
				return "\\" + ch;
			},


			// Used for iframes
			// See setDocument()
			// Removing the function wrapper causes a "Permission Denied"
			// error in IE
			unloadHandler = function unloadHandler() {
				setDocument();
			},
			    inDisabledFieldset = addCombinator(function (elem) {
				return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
			}, { dir: "parentNode", next: "legend" });

			// Optimize for push.apply( _, NodeList )
			try {
				push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes);
				// Support: Android<4.0
				// Detect silently failing push.apply
				arr[preferredDoc.childNodes.length].nodeType;
			} catch (e) {
				push = { apply: arr.length ?

					// Leverage slice if possible
					function (target, els) {
						push_native.apply(target, slice.call(els));
					} :

					// Support: IE<9
					// Otherwise append directly
					function (target, els) {
						var j = target.length,
						    i = 0;
						// Can't trust NodeList.length
						while (target[j++] = els[i++]) {}
						target.length = j - 1;
					}
				};
			}

			function Sizzle(selector, context, results, seed) {
				var m,
				    i,
				    elem,
				    nid,
				    match,
				    groups,
				    newSelector,
				    newContext = context && context.ownerDocument,


				// nodeType defaults to 9, since context defaults to document
				nodeType = context ? context.nodeType : 9;

				results = results || [];

				// Return early from calls with invalid selector or context
				if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {

					return results;
				}

				// Try to shortcut find operations (as opposed to filters) in HTML documents
				if (!seed) {

					if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
						setDocument(context);
					}
					context = context || document;

					if (documentIsHTML) {

						// If the selector is sufficiently simple, try using a "get*By*" DOM method
						// (excepting DocumentFragment context, where the methods don't exist)
						if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {

							// ID selector
							if (m = match[1]) {

								// Document context
								if (nodeType === 9) {
									if (elem = context.getElementById(m)) {

										// Support: IE, Opera, Webkit
										// TODO: identify versions
										// getElementById can match elements by name instead of ID
										if (elem.id === m) {
											results.push(elem);
											return results;
										}
									} else {
										return results;
									}

									// Element context
								} else {

									// Support: IE, Opera, Webkit
									// TODO: identify versions
									// getElementById can match elements by name instead of ID
									if (newContext && (elem = newContext.getElementById(m)) && contains(context, elem) && elem.id === m) {

										results.push(elem);
										return results;
									}
								}

								// Type selector
							} else if (match[2]) {
								push.apply(results, context.getElementsByTagName(selector));
								return results;

								// Class selector
							} else if ((m = match[3]) && support.getElementsByClassName && context.getElementsByClassName) {

								push.apply(results, context.getElementsByClassName(m));
								return results;
							}
						}

						// Take advantage of querySelectorAll
						if (support.qsa && !nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector)) && (

						// Support: IE 8 only
						// Exclude object elements
						nodeType !== 1 || context.nodeName.toLowerCase() !== "object")) {

							newSelector = selector;
							newContext = context;

							// qSA considers elements outside a scoping root when evaluating child or
							// descendant combinators, which is not what we want.
							// In such cases, we work around the behavior by prefixing every selector in the
							// list with an ID selector referencing the scope context.
							// Thanks to Andrew Dupont for this technique.
							if (nodeType === 1 && rdescend.test(selector)) {

								// Capture the context ID, setting it first if necessary
								if (nid = context.getAttribute("id")) {
									nid = nid.replace(rcssescape, fcssescape);
								} else {
									context.setAttribute("id", nid = expando);
								}

								// Prefix every selector in the list
								groups = tokenize(selector);
								i = groups.length;
								while (i--) {
									groups[i] = "#" + nid + " " + toSelector(groups[i]);
								}
								newSelector = groups.join(",");

								// Expand context for sibling selectors
								newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
							}

							try {
								push.apply(results, newContext.querySelectorAll(newSelector));
								return results;
							} catch (qsaError) {
								nonnativeSelectorCache(selector, true);
							} finally {
								if (nid === expando) {
									context.removeAttribute("id");
								}
							}
						}
					}
				}

				// All others
				return select(selector.replace(rtrim, "$1"), context, results, seed);
			}

			/**
    * Create key-value caches of limited size
    * @returns {function(string, object)} Returns the Object data after storing it on itself with
    *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
    *	deleting the oldest entry
    */
			function createCache() {
				var keys = [];

				function cache(key, value) {
					// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
					if (keys.push(key + " ") > Expr.cacheLength) {
						// Only keep the most recent entries
						delete cache[keys.shift()];
					}
					return cache[key + " "] = value;
				}
				return cache;
			}

			/**
    * Mark a function for special use by Sizzle
    * @param {Function} fn The function to mark
    */
			function markFunction(fn) {
				fn[expando] = true;
				return fn;
			}

			/**
    * Support testing using an element
    * @param {Function} fn Passed the created element and returns a boolean result
    */
			function assert(fn) {
				var el = document.createElement("fieldset");

				try {
					return !!fn(el);
				} catch (e) {
					return false;
				} finally {
					// Remove from its parent by default
					if (el.parentNode) {
						el.parentNode.removeChild(el);
					}
					// release memory in IE
					el = null;
				}
			}

			/**
    * Adds the same handler for all of the specified attrs
    * @param {String} attrs Pipe-separated list of attributes
    * @param {Function} handler The method that will be applied
    */
			function addHandle(attrs, handler) {
				var arr = attrs.split("|"),
				    i = arr.length;

				while (i--) {
					Expr.attrHandle[arr[i]] = handler;
				}
			}

			/**
    * Checks document order of two siblings
    * @param {Element} a
    * @param {Element} b
    * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
    */
			function siblingCheck(a, b) {
				var cur = b && a,
				    diff = cur && a.nodeType === 1 && b.nodeType === 1 && a.sourceIndex - b.sourceIndex;

				// Use IE sourceIndex if available on both nodes
				if (diff) {
					return diff;
				}

				// Check if b follows a
				if (cur) {
					while (cur = cur.nextSibling) {
						if (cur === b) {
							return -1;
						}
					}
				}

				return a ? 1 : -1;
			}

			/**
    * Returns a function to use in pseudos for input types
    * @param {String} type
    */
			function createInputPseudo(type) {
				return function (elem) {
					var name = elem.nodeName.toLowerCase();
					return name === "input" && elem.type === type;
				};
			}

			/**
    * Returns a function to use in pseudos for buttons
    * @param {String} type
    */
			function createButtonPseudo(type) {
				return function (elem) {
					var name = elem.nodeName.toLowerCase();
					return (name === "input" || name === "button") && elem.type === type;
				};
			}

			/**
    * Returns a function to use in pseudos for :enabled/:disabled
    * @param {Boolean} disabled true for :disabled; false for :enabled
    */
			function createDisabledPseudo(disabled) {

				// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
				return function (elem) {

					// Only certain elements can match :enabled or :disabled
					// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
					// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
					if ("form" in elem) {

						// Check for inherited disabledness on relevant non-disabled elements:
						// * listed form-associated elements in a disabled fieldset
						//   https://html.spec.whatwg.org/multipage/forms.html#category-listed
						//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
						// * option elements in a disabled optgroup
						//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
						// All such elements have a "form" property.
						if (elem.parentNode && elem.disabled === false) {

							// Option elements defer to a parent optgroup if present
							if ("label" in elem) {
								if ("label" in elem.parentNode) {
									return elem.parentNode.disabled === disabled;
								} else {
									return elem.disabled === disabled;
								}
							}

							// Support: IE 6 - 11
							// Use the isDisabled shortcut property to check for disabled fieldset ancestors
							return elem.isDisabled === disabled ||

							// Where there is no isDisabled, check manually
							/* jshint -W018 */
							elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled;
						}

						return elem.disabled === disabled;

						// Try to winnow out elements that can't be disabled before trusting the disabled property.
						// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
						// even exist on them, let alone have a boolean value.
					} else if ("label" in elem) {
						return elem.disabled === disabled;
					}

					// Remaining elements are neither :enabled nor :disabled
					return false;
				};
			}

			/**
    * Returns a function to use in pseudos for positionals
    * @param {Function} fn
    */
			function createPositionalPseudo(fn) {
				return markFunction(function (argument) {
					argument = +argument;
					return markFunction(function (seed, matches) {
						var j,
						    matchIndexes = fn([], seed.length, argument),
						    i = matchIndexes.length;

						// Match elements found at the specified indexes
						while (i--) {
							if (seed[j = matchIndexes[i]]) {
								seed[j] = !(matches[j] = seed[j]);
							}
						}
					});
				});
			}

			/**
    * Checks a node for validity as a Sizzle context
    * @param {Element|Object=} context
    * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
    */
			function testContext(context) {
				return context && typeof context.getElementsByTagName !== "undefined" && context;
			}

			// Expose support vars for convenience
			support = Sizzle.support = {};

			/**
    * Detects XML nodes
    * @param {Element|Object} elem An element or a document
    * @returns {Boolean} True iff elem is a non-HTML XML node
    */
			isXML = Sizzle.isXML = function (elem) {
				var namespace = elem.namespaceURI,
				    docElem = (elem.ownerDocument || elem).documentElement;

				// Support: IE <=8
				// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
				// https://bugs.jquery.com/ticket/4833
				return !rhtml.test(namespace || docElem && docElem.nodeName || "HTML");
			};

			/**
    * Sets document-related variables once based on the current document
    * @param {Element|Object} [doc] An element or document object to use to set the document
    * @returns {Object} Returns the current document
    */
			setDocument = Sizzle.setDocument = function (node) {
				var hasCompare,
				    subWindow,
				    doc = node ? node.ownerDocument || node : preferredDoc;

				// Return early if doc is invalid or already selected
				if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
					return document;
				}

				// Update global variables
				document = doc;
				docElem = document.documentElement;
				documentIsHTML = !isXML(document);

				// Support: IE 9-11, Edge
				// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
				if (preferredDoc !== document && (subWindow = document.defaultView) && subWindow.top !== subWindow) {

					// Support: IE 11, Edge
					if (subWindow.addEventListener) {
						subWindow.addEventListener("unload", unloadHandler, false);

						// Support: IE 9 - 10 only
					} else if (subWindow.attachEvent) {
						subWindow.attachEvent("onunload", unloadHandler);
					}
				}

				/* Attributes
    ---------------------------------------------------------------------- */

				// Support: IE<8
				// Verify that getAttribute really returns attributes and not properties
				// (excepting IE8 booleans)
				support.attributes = assert(function (el) {
					el.className = "i";
					return !el.getAttribute("className");
				});

				/* getElement(s)By*
    ---------------------------------------------------------------------- */

				// Check if getElementsByTagName("*") returns only elements
				support.getElementsByTagName = assert(function (el) {
					el.appendChild(document.createComment(""));
					return !el.getElementsByTagName("*").length;
				});

				// Support: IE<9
				support.getElementsByClassName = rnative.test(document.getElementsByClassName);

				// Support: IE<10
				// Check if getElementById returns elements by name
				// The broken getElementById methods don't pick up programmatically-set names,
				// so use a roundabout getElementsByName test
				support.getById = assert(function (el) {
					docElem.appendChild(el).id = expando;
					return !document.getElementsByName || !document.getElementsByName(expando).length;
				});

				// ID filter and find
				if (support.getById) {
					Expr.filter["ID"] = function (id) {
						var attrId = id.replace(runescape, funescape);
						return function (elem) {
							return elem.getAttribute("id") === attrId;
						};
					};
					Expr.find["ID"] = function (id, context) {
						if (typeof context.getElementById !== "undefined" && documentIsHTML) {
							var elem = context.getElementById(id);
							return elem ? [elem] : [];
						}
					};
				} else {
					Expr.filter["ID"] = function (id) {
						var attrId = id.replace(runescape, funescape);
						return function (elem) {
							var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
							return node && node.value === attrId;
						};
					};

					// Support: IE 6 - 7 only
					// getElementById is not reliable as a find shortcut
					Expr.find["ID"] = function (id, context) {
						if (typeof context.getElementById !== "undefined" && documentIsHTML) {
							var node,
							    i,
							    elems,
							    elem = context.getElementById(id);

							if (elem) {

								// Verify the id attribute
								node = elem.getAttributeNode("id");
								if (node && node.value === id) {
									return [elem];
								}

								// Fall back on getElementsByName
								elems = context.getElementsByName(id);
								i = 0;
								while (elem = elems[i++]) {
									node = elem.getAttributeNode("id");
									if (node && node.value === id) {
										return [elem];
									}
								}
							}

							return [];
						}
					};
				}

				// Tag
				Expr.find["TAG"] = support.getElementsByTagName ? function (tag, context) {
					if (typeof context.getElementsByTagName !== "undefined") {
						return context.getElementsByTagName(tag);

						// DocumentFragment nodes don't have gEBTN
					} else if (support.qsa) {
						return context.querySelectorAll(tag);
					}
				} : function (tag, context) {
					var elem,
					    tmp = [],
					    i = 0,

					// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
					results = context.getElementsByTagName(tag);

					// Filter out possible comments
					if (tag === "*") {
						while (elem = results[i++]) {
							if (elem.nodeType === 1) {
								tmp.push(elem);
							}
						}

						return tmp;
					}
					return results;
				};

				// Class
				Expr.find["CLASS"] = support.getElementsByClassName && function (className, context) {
					if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) {
						return context.getElementsByClassName(className);
					}
				};

				/* QSA/matchesSelector
    ---------------------------------------------------------------------- */

				// QSA and matchesSelector support

				// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
				rbuggyMatches = [];

				// qSa(:focus) reports false when true (Chrome 21)
				// We allow this because of a bug in IE8/9 that throws an error
				// whenever `document.activeElement` is accessed on an iframe
				// So, we allow :focus to pass through QSA all the time to avoid the IE error
				// See https://bugs.jquery.com/ticket/13378
				rbuggyQSA = [];

				if (support.qsa = rnative.test(document.querySelectorAll)) {
					// Build QSA regex
					// Regex strategy adopted from Diego Perini
					assert(function (el) {
						// Select is set to empty string on purpose
						// This is to test IE's treatment of not explicitly
						// setting a boolean content attribute,
						// since its presence should be enough
						// https://bugs.jquery.com/ticket/12359
						docElem.appendChild(el).innerHTML = "<a id='" + expando + "'></a>" + "<select id='" + expando + "-\r\\' msallowcapture=''>" + "<option selected=''></option></select>";

						// Support: IE8, Opera 11-12.16
						// Nothing should be selected when empty strings follow ^= or $= or *=
						// The test attribute must be unknown in Opera but "safe" for WinRT
						// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
						if (el.querySelectorAll("[msallowcapture^='']").length) {
							rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
						}

						// Support: IE8
						// Boolean attributes and "value" are not treated correctly
						if (!el.querySelectorAll("[selected]").length) {
							rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
						}

						// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
						if (!el.querySelectorAll("[id~=" + expando + "-]").length) {
							rbuggyQSA.push("~=");
						}

						// Webkit/Opera - :checked should return selected option elements
						// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
						// IE8 throws error here and will not see later tests
						if (!el.querySelectorAll(":checked").length) {
							rbuggyQSA.push(":checked");
						}

						// Support: Safari 8+, iOS 8+
						// https://bugs.webkit.org/show_bug.cgi?id=136851
						// In-page `selector#id sibling-combinator selector` fails
						if (!el.querySelectorAll("a#" + expando + "+*").length) {
							rbuggyQSA.push(".#.+[+~]");
						}
					});

					assert(function (el) {
						el.innerHTML = "<a href='' disabled='disabled'></a>" + "<select disabled='disabled'><option/></select>";

						// Support: Windows 8 Native Apps
						// The type and name attributes are restricted during .innerHTML assignment
						var input = document.createElement("input");
						input.setAttribute("type", "hidden");
						el.appendChild(input).setAttribute("name", "D");

						// Support: IE8
						// Enforce case-sensitivity of name attribute
						if (el.querySelectorAll("[name=d]").length) {
							rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
						}

						// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
						// IE8 throws error here and will not see later tests
						if (el.querySelectorAll(":enabled").length !== 2) {
							rbuggyQSA.push(":enabled", ":disabled");
						}

						// Support: IE9-11+
						// IE's :disabled selector does not pick up the children of disabled fieldsets
						docElem.appendChild(el).disabled = true;
						if (el.querySelectorAll(":disabled").length !== 2) {
							rbuggyQSA.push(":enabled", ":disabled");
						}

						// Opera 10-11 does not throw on post-comma invalid pseudos
						el.querySelectorAll("*,:x");
						rbuggyQSA.push(",.*:");
					});
				}

				if (support.matchesSelector = rnative.test(matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector)) {

					assert(function (el) {
						// Check to see if it's possible to do matchesSelector
						// on a disconnected node (IE 9)
						support.disconnectedMatch = matches.call(el, "*");

						// This should fail with an exception
						// Gecko does not error, returns false instead
						matches.call(el, "[s!='']:x");
						rbuggyMatches.push("!=", pseudos);
					});
				}

				rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
				rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));

				/* Contains
    ---------------------------------------------------------------------- */
				hasCompare = rnative.test(docElem.compareDocumentPosition);

				// Element contains another
				// Purposefully self-exclusive
				// As in, an element does not contain itself
				contains = hasCompare || rnative.test(docElem.contains) ? function (a, b) {
					var adown = a.nodeType === 9 ? a.documentElement : a,
					    bup = b && b.parentNode;
					return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
				} : function (a, b) {
					if (b) {
						while (b = b.parentNode) {
							if (b === a) {
								return true;
							}
						}
					}
					return false;
				};

				/* Sorting
    ---------------------------------------------------------------------- */

				// Document order sorting
				sortOrder = hasCompare ? function (a, b) {

					// Flag for duplicate removal
					if (a === b) {
						hasDuplicate = true;
						return 0;
					}

					// Sort on method existence if only one input has compareDocumentPosition
					var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
					if (compare) {
						return compare;
					}

					// Calculate position if both inputs belong to the same document
					compare = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) :

					// Otherwise we know they are disconnected
					1;

					// Disconnected nodes
					if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) {

						// Choose the first element that is related to our preferred document
						if (a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
							return -1;
						}
						if (b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
							return 1;
						}

						// Maintain original order
						return sortInput ? indexOf(sortInput, a) - indexOf(sortInput, b) : 0;
					}

					return compare & 4 ? -1 : 1;
				} : function (a, b) {
					// Exit early if the nodes are identical
					if (a === b) {
						hasDuplicate = true;
						return 0;
					}

					var cur,
					    i = 0,
					    aup = a.parentNode,
					    bup = b.parentNode,
					    ap = [a],
					    bp = [b];

					// Parentless nodes are either documents or disconnected
					if (!aup || !bup) {
						return a === document ? -1 : b === document ? 1 : aup ? -1 : bup ? 1 : sortInput ? indexOf(sortInput, a) - indexOf(sortInput, b) : 0;

						// If the nodes are siblings, we can do a quick check
					} else if (aup === bup) {
						return siblingCheck(a, b);
					}

					// Otherwise we need full lists of their ancestors for comparison
					cur = a;
					while (cur = cur.parentNode) {
						ap.unshift(cur);
					}
					cur = b;
					while (cur = cur.parentNode) {
						bp.unshift(cur);
					}

					// Walk down the tree looking for a discrepancy
					while (ap[i] === bp[i]) {
						i++;
					}

					return i ?
					// Do a sibling check if the nodes have a common ancestor
					siblingCheck(ap[i], bp[i]) :

					// Otherwise nodes in our document sort first
					ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0;
				};

				return document;
			};

			Sizzle.matches = function (expr, elements) {
				return Sizzle(expr, null, null, elements);
			};

			Sizzle.matchesSelector = function (elem, expr) {
				// Set document vars if needed
				if ((elem.ownerDocument || elem) !== document) {
					setDocument(elem);
				}

				if (support.matchesSelector && documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyMatches || !rbuggyMatches.test(expr)) && (!rbuggyQSA || !rbuggyQSA.test(expr))) {

					try {
						var ret = matches.call(elem, expr);

						// IE 9's matchesSelector returns false on disconnected nodes
						if (ret || support.disconnectedMatch ||
						// As well, disconnected nodes are said to be in a document
						// fragment in IE 9
						elem.document && elem.document.nodeType !== 11) {
							return ret;
						}
					} catch (e) {
						nonnativeSelectorCache(expr, true);
					}
				}

				return Sizzle(expr, document, null, [elem]).length > 0;
			};

			Sizzle.contains = function (context, elem) {
				// Set document vars if needed
				if ((context.ownerDocument || context) !== document) {
					setDocument(context);
				}
				return contains(context, elem);
			};

			Sizzle.attr = function (elem, name) {
				// Set document vars if needed
				if ((elem.ownerDocument || elem) !== document) {
					setDocument(elem);
				}

				var fn = Expr.attrHandle[name.toLowerCase()],

				// Don't get fooled by Object.prototype properties (jQuery #13807)
				val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined;

				return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute(name) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null;
			};

			Sizzle.escape = function (sel) {
				return (sel + "").replace(rcssescape, fcssescape);
			};

			Sizzle.error = function (msg) {
				throw new Error("Syntax error, unrecognized expression: " + msg);
			};

			/**
    * Document sorting and removing duplicates
    * @param {ArrayLike} results
    */
			Sizzle.uniqueSort = function (results) {
				var elem,
				    duplicates = [],
				    j = 0,
				    i = 0;

				// Unless we *know* we can detect duplicates, assume their presence
				hasDuplicate = !support.detectDuplicates;
				sortInput = !support.sortStable && results.slice(0);
				results.sort(sortOrder);

				if (hasDuplicate) {
					while (elem = results[i++]) {
						if (elem === results[i]) {
							j = duplicates.push(i);
						}
					}
					while (j--) {
						results.splice(duplicates[j], 1);
					}
				}

				// Clear input after sorting to release objects
				// See https://github.com/jquery/sizzle/pull/225
				sortInput = null;

				return results;
			};

			/**
    * Utility function for retrieving the text value of an array of DOM nodes
    * @param {Array|Element} elem
    */
			getText = Sizzle.getText = function (elem) {
				var node,
				    ret = "",
				    i = 0,
				    nodeType = elem.nodeType;

				if (!nodeType) {
					// If no nodeType, this is expected to be an array
					while (node = elem[i++]) {
						// Do not traverse comment nodes
						ret += getText(node);
					}
				} else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
					// Use textContent for elements
					// innerText usage removed for consistency of new lines (jQuery #11153)
					if (typeof elem.textContent === "string") {
						return elem.textContent;
					} else {
						// Traverse its children
						for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
							ret += getText(elem);
						}
					}
				} else if (nodeType === 3 || nodeType === 4) {
					return elem.nodeValue;
				}
				// Do not include comment or processing instruction nodes

				return ret;
			};

			Expr = Sizzle.selectors = {

				// Can be adjusted by the user
				cacheLength: 50,

				createPseudo: markFunction,

				match: matchExpr,

				attrHandle: {},

				find: {},

				relative: {
					">": { dir: "parentNode", first: true },
					" ": { dir: "parentNode" },
					"+": { dir: "previousSibling", first: true },
					"~": { dir: "previousSibling" }
				},

				preFilter: {
					"ATTR": function ATTR(match) {
						match[1] = match[1].replace(runescape, funescape);

						// Move the given value to match[3] whether quoted or unquoted
						match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);

						if (match[2] === "~=") {
							match[3] = " " + match[3] + " ";
						}

						return match.slice(0, 4);
					},

					"CHILD": function CHILD(match) {
						/* matches from matchExpr["CHILD"]
      	1 type (only|nth|...)
      	2 what (child|of-type)
      	3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
      	4 xn-component of xn+y argument ([+-]?\d*n|)
      	5 sign of xn-component
      	6 x of xn-component
      	7 sign of y-component
      	8 y of y-component
      */
						match[1] = match[1].toLowerCase();

						if (match[1].slice(0, 3) === "nth") {
							// nth-* requires argument
							if (!match[3]) {
								Sizzle.error(match[0]);
							}

							// numeric x and y parameters for Expr.filter.CHILD
							// remember that false/true cast respectively to 0/1
							match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
							match[5] = +(match[7] + match[8] || match[3] === "odd");

							// other types prohibit arguments
						} else if (match[3]) {
							Sizzle.error(match[0]);
						}

						return match;
					},

					"PSEUDO": function PSEUDO(match) {
						var excess,
						    unquoted = !match[6] && match[2];

						if (matchExpr["CHILD"].test(match[0])) {
							return null;
						}

						// Accept quoted arguments as-is
						if (match[3]) {
							match[2] = match[4] || match[5] || "";

							// Strip excess characters from unquoted arguments
						} else if (unquoted && rpseudo.test(unquoted) && (
						// Get excess from tokenize (recursively)
						excess = tokenize(unquoted, true)) && (
						// advance to the next closing parenthesis
						excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {

							// excess is a negative index
							match[0] = match[0].slice(0, excess);
							match[2] = unquoted.slice(0, excess);
						}

						// Return only captures needed by the pseudo filter method (type and argument)
						return match.slice(0, 3);
					}
				},

				filter: {

					"TAG": function TAG(nodeNameSelector) {
						var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
						return nodeNameSelector === "*" ? function () {
							return true;
						} : function (elem) {
							return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
						};
					},

					"CLASS": function CLASS(className) {
						var pattern = classCache[className + " "];

						return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function (elem) {
							return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "");
						});
					},

					"ATTR": function ATTR(name, operator, check) {
						return function (elem) {
							var result = Sizzle.attr(elem, name);

							if (result == null) {
								return operator === "!=";
							}
							if (!operator) {
								return true;
							}

							result += "";

							return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf(check) === 0 : operator === "*=" ? check && result.indexOf(check) > -1 : operator === "$=" ? check && result.slice(-check.length) === check : operator === "~=" ? (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" : false;
						};
					},

					"CHILD": function CHILD(type, what, argument, first, last) {
						var simple = type.slice(0, 3) !== "nth",
						    forward = type.slice(-4) !== "last",
						    ofType = what === "of-type";

						return first === 1 && last === 0 ?

						// Shortcut for :nth-*(n)
						function (elem) {
							return !!elem.parentNode;
						} : function (elem, context, xml) {
							var cache,
							    uniqueCache,
							    outerCache,
							    node,
							    nodeIndex,
							    start,
							    dir = simple !== forward ? "nextSibling" : "previousSibling",
							    parent = elem.parentNode,
							    name = ofType && elem.nodeName.toLowerCase(),
							    useCache = !xml && !ofType,
							    diff = false;

							if (parent) {

								// :(first|last|only)-(child|of-type)
								if (simple) {
									while (dir) {
										node = elem;
										while (node = node[dir]) {
											if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {

												return false;
											}
										}
										// Reverse direction for :only-* (if we haven't yet done so)
										start = dir = type === "only" && !start && "nextSibling";
									}
									return true;
								}

								start = [forward ? parent.firstChild : parent.lastChild];

								// non-xml :nth-child(...) stores cache data on `parent`
								if (forward && useCache) {

									// Seek `elem` from a previously-cached index

									// ...in a gzip-friendly way
									node = parent;
									outerCache = node[expando] || (node[expando] = {});

									// Support: IE <9 only
									// Defend against cloned attroperties (jQuery gh-1709)
									uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});

									cache = uniqueCache[type] || [];
									nodeIndex = cache[0] === dirruns && cache[1];
									diff = nodeIndex && cache[2];
									node = nodeIndex && parent.childNodes[nodeIndex];

									while (node = ++nodeIndex && node && node[dir] || (

									// Fallback to seeking `elem` from the start
									diff = nodeIndex = 0) || start.pop()) {

										// When found, cache indexes on `parent` and break
										if (node.nodeType === 1 && ++diff && node === elem) {
											uniqueCache[type] = [dirruns, nodeIndex, diff];
											break;
										}
									}
								} else {
									// Use previously-cached element index if available
									if (useCache) {
										// ...in a gzip-friendly way
										node = elem;
										outerCache = node[expando] || (node[expando] = {});

										// Support: IE <9 only
										// Defend against cloned attroperties (jQuery gh-1709)
										uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});

										cache = uniqueCache[type] || [];
										nodeIndex = cache[0] === dirruns && cache[1];
										diff = nodeIndex;
									}

									// xml :nth-child(...)
									// or :nth-last-child(...) or :nth(-last)?-of-type(...)
									if (diff === false) {
										// Use the same loop as above to seek `elem` from the start
										while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) {

											if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {

												// Cache the index of each encountered element
												if (useCache) {
													outerCache = node[expando] || (node[expando] = {});

													// Support: IE <9 only
													// Defend against cloned attroperties (jQuery gh-1709)
													uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});

													uniqueCache[type] = [dirruns, diff];
												}

												if (node === elem) {
													break;
												}
											}
										}
									}
								}

								// Incorporate the offset, then check against cycle size
								diff -= last;
								return diff === first || diff % first === 0 && diff / first >= 0;
							}
						};
					},

					"PSEUDO": function PSEUDO(pseudo, argument) {
						// pseudo-class names are case-insensitive
						// http://www.w3.org/TR/selectors/#pseudo-classes
						// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
						// Remember that setFilters inherits from pseudos
						var args,
						    fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error("unsupported pseudo: " + pseudo);

						// The user may use createPseudo to indicate that
						// arguments are needed to create the filter function
						// just as Sizzle does
						if (fn[expando]) {
							return fn(argument);
						}

						// But maintain support for old signatures
						if (fn.length > 1) {
							args = [pseudo, pseudo, "", argument];
							return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function (seed, matches) {
								var idx,
								    matched = fn(seed, argument),
								    i = matched.length;
								while (i--) {
									idx = indexOf(seed, matched[i]);
									seed[idx] = !(matches[idx] = matched[i]);
								}
							}) : function (elem) {
								return fn(elem, 0, args);
							};
						}

						return fn;
					}
				},

				pseudos: {
					// Potentially complex pseudos
					"not": markFunction(function (selector) {
						// Trim the selector passed to compile
						// to avoid treating leading and trailing
						// spaces as combinators
						var input = [],
						    results = [],
						    matcher = compile(selector.replace(rtrim, "$1"));

						return matcher[expando] ? markFunction(function (seed, matches, context, xml) {
							var elem,
							    unmatched = matcher(seed, null, xml, []),
							    i = seed.length;

							// Match elements unmatched by `matcher`
							while (i--) {
								if (elem = unmatched[i]) {
									seed[i] = !(matches[i] = elem);
								}
							}
						}) : function (elem, context, xml) {
							input[0] = elem;
							matcher(input, null, xml, results);
							// Don't keep the element (issue #299)
							input[0] = null;
							return !results.pop();
						};
					}),

					"has": markFunction(function (selector) {
						return function (elem) {
							return Sizzle(selector, elem).length > 0;
						};
					}),

					"contains": markFunction(function (text) {
						text = text.replace(runescape, funescape);
						return function (elem) {
							return (elem.textContent || getText(elem)).indexOf(text) > -1;
						};
					}),

					// "Whether an element is represented by a :lang() selector
					// is based solely on the element's language value
					// being equal to the identifier C,
					// or beginning with the identifier C immediately followed by "-".
					// The matching of C against the element's language value is performed case-insensitively.
					// The identifier C does not have to be a valid language name."
					// http://www.w3.org/TR/selectors/#lang-pseudo
					"lang": markFunction(function (lang) {
						// lang value must be a valid identifier
						if (!ridentifier.test(lang || "")) {
							Sizzle.error("unsupported lang: " + lang);
						}
						lang = lang.replace(runescape, funescape).toLowerCase();
						return function (elem) {
							var elemLang;
							do {
								if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {

									elemLang = elemLang.toLowerCase();
									return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
								}
							} while ((elem = elem.parentNode) && elem.nodeType === 1);
							return false;
						};
					}),

					// Miscellaneous
					"target": function target(elem) {
						var hash = window.location && window.location.hash;
						return hash && hash.slice(1) === elem.id;
					},

					"root": function root(elem) {
						return elem === docElem;
					},

					"focus": function focus(elem) {
						return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
					},

					// Boolean properties
					"enabled": createDisabledPseudo(false),
					"disabled": createDisabledPseudo(true),

					"checked": function checked(elem) {
						// In CSS3, :checked should return both checked and selected elements
						// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
						var nodeName = elem.nodeName.toLowerCase();
						return nodeName === "input" && !!elem.checked || nodeName === "option" && !!elem.selected;
					},

					"selected": function selected(elem) {
						// Accessing this property makes selected-by-default
						// options in Safari work properly
						if (elem.parentNode) {
							elem.parentNode.selectedIndex;
						}

						return elem.selected === true;
					},

					// Contents
					"empty": function empty(elem) {
						// http://www.w3.org/TR/selectors/#empty-pseudo
						// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
						//   but not by others (comment: 8; processing instruction: 7; etc.)
						// nodeType < 6 works because attributes (2) do not appear as children
						for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
							if (elem.nodeType < 6) {
								return false;
							}
						}
						return true;
					},

					"parent": function parent(elem) {
						return !Expr.pseudos["empty"](elem);
					},

					// Element/input types
					"header": function header(elem) {
						return rheader.test(elem.nodeName);
					},

					"input": function input(elem) {
						return rinputs.test(elem.nodeName);
					},

					"button": function button(elem) {
						var name = elem.nodeName.toLowerCase();
						return name === "input" && elem.type === "button" || name === "button";
					},

					"text": function text(elem) {
						var attr;
						return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && (

						// Support: IE<8
						// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
						(attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
					},

					// Position-in-collection
					"first": createPositionalPseudo(function () {
						return [0];
					}),

					"last": createPositionalPseudo(function (matchIndexes, length) {
						return [length - 1];
					}),

					"eq": createPositionalPseudo(function (matchIndexes, length, argument) {
						return [argument < 0 ? argument + length : argument];
					}),

					"even": createPositionalPseudo(function (matchIndexes, length) {
						var i = 0;
						for (; i < length; i += 2) {
							matchIndexes.push(i);
						}
						return matchIndexes;
					}),

					"odd": createPositionalPseudo(function (matchIndexes, length) {
						var i = 1;
						for (; i < length; i += 2) {
							matchIndexes.push(i);
						}
						return matchIndexes;
					}),

					"lt": createPositionalPseudo(function (matchIndexes, length, argument) {
						var i = argument < 0 ? argument + length : argument > length ? length : argument;
						for (; --i >= 0;) {
							matchIndexes.push(i);
						}
						return matchIndexes;
					}),

					"gt": createPositionalPseudo(function (matchIndexes, length, argument) {
						var i = argument < 0 ? argument + length : argument;
						for (; ++i < length;) {
							matchIndexes.push(i);
						}
						return matchIndexes;
					})
				}
			};

			Expr.pseudos["nth"] = Expr.pseudos["eq"];

			// Add button/input type pseudos
			for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
				Expr.pseudos[i] = createInputPseudo(i);
			}
			for (i in { submit: true, reset: true }) {
				Expr.pseudos[i] = createButtonPseudo(i);
			}

			// Easy API for creating new setFilters
			function setFilters() {}
			setFilters.prototype = Expr.filters = Expr.pseudos;
			Expr.setFilters = new setFilters();

			tokenize = Sizzle.tokenize = function (selector, parseOnly) {
				var matched,
				    match,
				    tokens,
				    type,
				    soFar,
				    groups,
				    preFilters,
				    cached = tokenCache[selector + " "];

				if (cached) {
					return parseOnly ? 0 : cached.slice(0);
				}

				soFar = selector;
				groups = [];
				preFilters = Expr.preFilter;

				while (soFar) {

					// Comma and first run
					if (!matched || (match = rcomma.exec(soFar))) {
						if (match) {
							// Don't consume trailing commas as valid
							soFar = soFar.slice(match[0].length) || soFar;
						}
						groups.push(tokens = []);
					}

					matched = false;

					// Combinators
					if (match = rcombinators.exec(soFar)) {
						matched = match.shift();
						tokens.push({
							value: matched,
							// Cast descendant combinators to space
							type: match[0].replace(rtrim, " ")
						});
						soFar = soFar.slice(matched.length);
					}

					// Filters
					for (type in Expr.filter) {
						if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
							matched = match.shift();
							tokens.push({
								value: matched,
								type: type,
								matches: match
							});
							soFar = soFar.slice(matched.length);
						}
					}

					if (!matched) {
						break;
					}
				}

				// Return the length of the invalid excess
				// if we're just parsing
				// Otherwise, throw an error or return tokens
				return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :
				// Cache the tokens
				tokenCache(selector, groups).slice(0);
			};

			function toSelector(tokens) {
				var i = 0,
				    len = tokens.length,
				    selector = "";
				for (; i < len; i++) {
					selector += tokens[i].value;
				}
				return selector;
			}

			function addCombinator(matcher, combinator, base) {
				var dir = combinator.dir,
				    skip = combinator.next,
				    key = skip || dir,
				    checkNonElements = base && key === "parentNode",
				    doneName = done++;

				return combinator.first ?
				// Check against closest ancestor/preceding element
				function (elem, context, xml) {
					while (elem = elem[dir]) {
						if (elem.nodeType === 1 || checkNonElements) {
							return matcher(elem, context, xml);
						}
					}
					return false;
				} :

				// Check against all ancestor/preceding elements
				function (elem, context, xml) {
					var oldCache,
					    uniqueCache,
					    outerCache,
					    newCache = [dirruns, doneName];

					// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
					if (xml) {
						while (elem = elem[dir]) {
							if (elem.nodeType === 1 || checkNonElements) {
								if (matcher(elem, context, xml)) {
									return true;
								}
							}
						}
					} else {
						while (elem = elem[dir]) {
							if (elem.nodeType === 1 || checkNonElements) {
								outerCache = elem[expando] || (elem[expando] = {});

								// Support: IE <9 only
								// Defend against cloned attroperties (jQuery gh-1709)
								uniqueCache = outerCache[elem.uniqueID] || (outerCache[elem.uniqueID] = {});

								if (skip && skip === elem.nodeName.toLowerCase()) {
									elem = elem[dir] || elem;
								} else if ((oldCache = uniqueCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) {

									// Assign to newCache so results back-propagate to previous elements
									return newCache[2] = oldCache[2];
								} else {
									// Reuse newcache so results back-propagate to previous elements
									uniqueCache[key] = newCache;

									// A match means we're done; a fail means we have to keep checking
									if (newCache[2] = matcher(elem, context, xml)) {
										return true;
									}
								}
							}
						}
					}
					return false;
				};
			}

			function elementMatcher(matchers) {
				return matchers.length > 1 ? function (elem, context, xml) {
					var i = matchers.length;
					while (i--) {
						if (!matchers[i](elem, context, xml)) {
							return false;
						}
					}
					return true;
				} : matchers[0];
			}

			function multipleContexts(selector, contexts, results) {
				var i = 0,
				    len = contexts.length;
				for (; i < len; i++) {
					Sizzle(selector, contexts[i], results);
				}
				return results;
			}

			function condense(unmatched, map, filter, context, xml) {
				var elem,
				    newUnmatched = [],
				    i = 0,
				    len = unmatched.length,
				    mapped = map != null;

				for (; i < len; i++) {
					if (elem = unmatched[i]) {
						if (!filter || filter(elem, context, xml)) {
							newUnmatched.push(elem);
							if (mapped) {
								map.push(i);
							}
						}
					}
				}

				return newUnmatched;
			}

			function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
				if (postFilter && !postFilter[expando]) {
					postFilter = setMatcher(postFilter);
				}
				if (postFinder && !postFinder[expando]) {
					postFinder = setMatcher(postFinder, postSelector);
				}
				return markFunction(function (seed, results, context, xml) {
					var temp,
					    i,
					    elem,
					    preMap = [],
					    postMap = [],
					    preexisting = results.length,


					// Get initial elements from seed or context
					elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),


					// Prefilter to get matcher input, preserving a map for seed-results synchronization
					matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems,
					    matcherOut = matcher ?
					// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
					postFinder || (seed ? preFilter : preexisting || postFilter) ?

					// ...intermediate processing is necessary
					[] :

					// ...otherwise use results directly
					results : matcherIn;

					// Find primary matches
					if (matcher) {
						matcher(matcherIn, matcherOut, context, xml);
					}

					// Apply postFilter
					if (postFilter) {
						temp = condense(matcherOut, postMap);
						postFilter(temp, [], context, xml);

						// Un-match failing elements by moving them back to matcherIn
						i = temp.length;
						while (i--) {
							if (elem = temp[i]) {
								matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
							}
						}
					}

					if (seed) {
						if (postFinder || preFilter) {
							if (postFinder) {
								// Get the final matcherOut by condensing this intermediate into postFinder contexts
								temp = [];
								i = matcherOut.length;
								while (i--) {
									if (elem = matcherOut[i]) {
										// Restore matcherIn since elem is not yet a final match
										temp.push(matcherIn[i] = elem);
									}
								}
								postFinder(null, matcherOut = [], temp, xml);
							}

							// Move matched elements from seed to results to keep them synchronized
							i = matcherOut.length;
							while (i--) {
								if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf(seed, elem) : preMap[i]) > -1) {

									seed[temp] = !(results[temp] = elem);
								}
							}
						}

						// Add elements to results, through postFinder if defined
					} else {
						matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
						if (postFinder) {
							postFinder(null, results, matcherOut, xml);
						} else {
							push.apply(results, matcherOut);
						}
					}
				});
			}

			function matcherFromTokens(tokens) {
				var checkContext,
				    matcher,
				    j,
				    len = tokens.length,
				    leadingRelative = Expr.relative[tokens[0].type],
				    implicitRelative = leadingRelative || Expr.relative[" "],
				    i = leadingRelative ? 1 : 0,


				// The foundational matcher ensures that elements are reachable from top-level context(s)
				matchContext = addCombinator(function (elem) {
					return elem === checkContext;
				}, implicitRelative, true),
				    matchAnyContext = addCombinator(function (elem) {
					return indexOf(checkContext, elem) > -1;
				}, implicitRelative, true),
				    matchers = [function (elem, context, xml) {
					var ret = !leadingRelative && (xml || context !== outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
					// Avoid hanging onto element (issue #299)
					checkContext = null;
					return ret;
				}];

				for (; i < len; i++) {
					if (matcher = Expr.relative[tokens[i].type]) {
						matchers = [addCombinator(elementMatcher(matchers), matcher)];
					} else {
						matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);

						// Return special upon seeing a positional matcher
						if (matcher[expando]) {
							// Find the next relative operator (if any) for proper handling
							j = ++i;
							for (; j < len; j++) {
								if (Expr.relative[tokens[j].type]) {
									break;
								}
							}
							return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(
							// If the preceding token was a descendant combinator, insert an implicit any-element `*`
							tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens));
						}
						matchers.push(matcher);
					}
				}

				return elementMatcher(matchers);
			}

			function matcherFromGroupMatchers(elementMatchers, setMatchers) {
				var bySet = setMatchers.length > 0,
				    byElement = elementMatchers.length > 0,
				    superMatcher = function superMatcher(seed, context, xml, results, outermost) {
					var elem,
					    j,
					    matcher,
					    matchedCount = 0,
					    i = "0",
					    unmatched = seed && [],
					    setMatched = [],