diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/.gitignore b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/.gitignore new file mode 100644 index 0000000..a21bcfe --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/.gitignore @@ -0,0 +1,7 @@ +/node_modules +#* +*~ +.tern-port +npm-debug.log +/old +/build diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/LICENSE.md b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/LICENSE.md new file mode 100644 index 0000000..16d89e0 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/LICENSE.md @@ -0,0 +1,596 @@ +GNU GENERAL PUBLIC LICENSE +========================== + +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert +copyright on the software, and (2) offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions. + +“This License” refers to version 3 of the GNU General Public License. + +“Copyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +“The Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as “you”. “Licensees” and +“recipients” may be individuals or organizations. + +To “modify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a “modified version” of the earlier work or a +work “based on” the earlier work. + +A “covered work” means either the unmodified Program or a work based on +the Program. + +To “propagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To “convey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays “Appropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that (1) +displays an appropriate copyright notice, and (2) tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code. + +The “source code” for a work means the preferred form of the work for +making modifications to it. “Object code” means any non-source form of a +work. + +A “Standard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The “System Libraries” of an executable work include anything, other than +the work as a whole, that (a) is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and (b) serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A “Major Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The “Corresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions. + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to “keep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an “aggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either (1) a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or (2) access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A “User Product” is either (1) a “consumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or (2) anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, “normally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +“Installation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms. + +“Additional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered “further +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination. + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated (a) provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and (b) permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An “entity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents. + +A “contributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's “contributor version”. + +A contributor's “essential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, “control” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a “patent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To “grant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either (1) cause the Corresponding +Source to be so available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. “Knowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is “discriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license (a) in connection with +copies of the covered work conveyed by you (or copies made from those copies), or (b) +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License “or any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the “copyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an “about box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a “copyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. \ No newline at end of file diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/README.md b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/README.md new file mode 100644 index 0000000..6c64689 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/README.md @@ -0,0 +1,48 @@ +What Every Hipster Should Know About Functional Reactive Programming +==================================================================== + +Original source at [github.com/bodil/boogaloo](https://github.com/bodil/boogaloo). + +It is a slide deck. Much code. + +Navigate through slides using `PgUp` and `PgDn`. + +Editor cheat sheet: + +* `Ctrl-S` evaluates the whole buffer. +* `Ctrl-D` evaluates the top level expression at cursor point. +* `Ctrl-R` reloads the HTML document without evaluating the buffer. +* `Ctrl-,` toggles commenting of the current line or selection. +* `Ctrl-'` selects the token at point. +* `Ctrl-\` invokes autocomplete on the token at point. +* `Ctrl-I` shows the inferred type of the token at point. +* `Ctrl-Q` renames the variable at point. +* `Alt-.` jumps to the definition of the token at point. +* `Alt-,` jumps back. +* `Ctrl-K` and `Ctrl-Y` kills to end of line and yanks from the kill buffer as in Most Holy Emacs. +* `Ctrl-A` and `Ctrl-E` similarly moves cursor to start and end of line. +* `Tab` will indent the current line to where it's supposed to be. +* `Alt-Space` sends a space bar keypress event to the HTML document. +* etc. for enter and cursor keys. +* Finally, `Esc` moves focus from the editor back to the slide deck, so you can change slides etc. (Also, if the slide deck is active, `Tab` should focus the editor.) + +License +------- + +Unless otherwise noted in source code, the GPL v3 applies: + +Copyright 2014 Bodil Stokke + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +[http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/es6-loader.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/es6-loader.js new file mode 100644 index 0000000..fc8ed5d --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/es6-loader.js @@ -0,0 +1,29 @@ +/*global Buffer */ + +var traceur = require("traceur"); + +function throwErrors(errs) { + return "throw new Error(\'ES6 compilation failed.\\n" + + errs.map(function(l) { + return l.replace(/'/g, "\\\'").replace(/"/g, "\\\""); + }).join("\\n") + "\');\n"; +} + +module.exports = function(source) { + var callback = this.async(); + this.cacheable(); + var out = traceur.compile(source, { + filename: this.resourcePath, + modules: "commonjs", + sourceMap: true, + blockBinding: true, + symbols: true, + deferredFunctions: true, + types: true, + annotations: true + }); + out.errors.forEach(function(err) { + this.emitError(err); + }, this); + this.callback(null, out.js || throwErrors(out.errors), out.sourceMap); +}; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/webpack.config.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/webpack.config.js new file mode 100644 index 0000000..f98428b --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/config/webpack.config.js @@ -0,0 +1,49 @@ +var OccurenceOrderPlugin = require("webpack/lib/optimize/OccurenceOrderPlugin"); +var DedupePlugin = require("webpack/lib/optimize/DedupePlugin"); +var UglifyPlugin = require("webpack/lib/optimize/UglifyJsPlugin"); + +var srcPath = require("path").join(__dirname, "..", "src"); +var buildPath = require("path").join(__dirname, "..", "build"); + +module.exports = { + bail: true, + cache: true, + context: srcPath, + entry: "./main.es6", + output: { + path: buildPath, + filename: "slide.js", + publicPath: "build/" + }, + module: { + loaders: [ + { test: /\.less$/, loader: "style!css!less" }, + { test: /\.css$/, loader: "style!css" }, + { test: /\.json$/, loader: "json" }, + { test: /\.png$/, loader: "url?limit=10000&mimetype=image/png" }, + { test: /\.svg$/, loader: "url?limit=10000&mimetype=image/svg" }, + { test: /\.otf$/, loader: "url?limit=10000&mimetype=application/x-font-otf" }, + { test: /\.ttf$/, loader: "url?limit=10000&mimetype=application/x-font-ttf" }, + { test: /\.mp3$/, loader: "url?limit=10000&mimetype=audio/mpeg" }, + { test: /\.html$/, loader: "url?limit=10000&mimetype=text/html" }, + { test: /\.es6$/, loader: require("path").join(__dirname, "es6-loader.js") } + ] + }, + devtool: "source-map", + resolve: { + extensions: ["", ".es6", ".js"] + // Webpack seems to have trouble resolving some Rx modules; workaround: + // fallback: require("path").join(__dirname, "..", "node_modules/rx") + }, + node: { + "global": true, + "process": true, + "__filename": true, + "__dirname": true + }, + plugins: [ + new OccurenceOrderPlugin(), + new DedupePlugin(), + new UglifyPlugin() + ] +}; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/es6/game.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/es6/game.js new file mode 100644 index 0000000..9c36ecb --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/es6/game.js @@ -0,0 +1,161 @@ +/*global React, Rx, Audio */ + +function deepCopy(target, obj) { + for (let prop in obj) + if (obj.hasOwnProperty(prop)) + if (typeof obj[prop] === "object") + target[prop] = deepCopy({}, obj[prop]); + else target[prop] = obj[prop]; +} + +function assoc(...args) { + let out = {}; + for (let i = 0; i < args.length; i++) + deepCopy(out, args[i]); + return out; +} + +function bounds(me) { + return { + x1: me.x + (me.baseX || 0), + y1: me.y + (me.baseY || 0), + x2: me.x + (me.baseX || 0) + 100, + y2: me.y + (me.baseY || 0) + 100 + }; +} + +function intersects(me, target) { + let b1 = bounds(me), b2 = bounds(target); + return !(b2.x1 > b1.x2 || b2.x2 < b1.x1 || + b2.y1 > b1.y2 || b2.y2 < b1.y1); +} + +const canvas = document.getElementById("canvas"); + +function onscreen(node) { + return !(node.x < -300 || node.y < -1000 || node.y > 1000); +} + +function makeElement(node) { + return React.DOM.div({ + className: node.id, + style: { + left: Math.floor(node.x + (node.baseX || 0)) + "px", + top: Math.floor(node.y + (node.baseY || 0)) + "px" + } + }); +} + +function renderScene(nodes) { + return React.renderComponent( + React.DOM.div(null, nodes.map(makeElement)), + canvas + ); +} + +function bindKey(key) { + let sub = new Rx.Subject(); + Mousetrap.bind(key, () => { + sub.onNext(key); + }); + return sub; +} + +let groundStream = Rx.Observable.interval(33) + .map((x) => ({ + id: "ground", + baseX: -128, + x: ((x % 64) * -8), y: 384 + })); + +function velocity(node) { + return assoc(node, { + x: node.x + node.vx, + y: node.y + node.vy + }); +} + +let tick = bindKey("space") + .buffer(Rx.Observable.interval(33)); + +let initialHater = { + id: "hater", + vx: -8, vy: 0, + x: 1600, y: 300 +}; + +let haterStream = tick.scan(initialHater, (c, keys) => { + // Apply velocity to position. + c = velocity(c); + return onscreen(c) ? c : initialHater; +}); + +let pinkieStream = Rx.Observable.zipArray(tick, haterStream).scan({ + id: "pinkie", + baseY: 276, + x: 0, y: 0, + vx: 0, vy: 0, + gameOver: false +}, (p, [keys, hater]) => { + p = velocity(p); + + if (intersects(p, hater)) { + p.gameOver = true; + p.id = "pinkie gameover"; + new Audio("sfx/gameover.mp3").play(); + p.vy = -15; + } + if (p.gameOver) { + p.vy += 0.5; + return p; + } + + // Apply gravity to Pinkie's velocity. + p.vy += 0.98; + + // AS Pinkie Pie, + // GIVEN that I'm falling + // WHEN I hit the ground + // THEN I stop. + if (p.y >= 0 && p.vy > 0) { + p.y = 0; p.vy = 0; + } + + // If Pinkie is on the ground and space has been pressed, JUMP. + if (keys[0] === "space") { + // p.vy = -20; // wheeee infinite jump + if (p.y === 0) { + p.vy = -20; + new Audio("sfx/jump.mp3").play(); + } + } + + p.id = (p.y < 0) ? "pinkie jumping" : "pinkie"; + + return p; +}).takeWhile(onscreen); + +let initialCoin = { + id: "coin", + vx: -6, vy: 0, + x: 1600, y: 40 +}; + +let coinStream = pinkieStream.scan(initialCoin, (c, pinkie) => { + // Apply velocity to position. + c = velocity(c); + + // If Pinkie touches the coin, ding it! + if (c.vy === 0 && intersects(c, pinkie)) { + new Audio("sfx/coin.mp3").play(); + c.vx = 0; c.vy = -1; + } + if (c.vy < 0) { + c.vy = c.vy * 2; + } + + return onscreen(c) ? c : initialCoin; +}); + +Rx.Observable.zipArray(pinkieStream, groundStream, coinStream, haterStream) + .subscribe(renderScene); diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.css new file mode 100644 index 0000000..99b9f4e --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.css @@ -0,0 +1,65 @@ +*, *:before, *:after { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0; +} + +#canvas { + position: absolute; + top: 0; + left: 0; + width: 512px; + height: 512px; + background: url(gfx/clouds.png); + background-size: cover; + overflow: hidden; + -moz-transform-origin: 0 0; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; +} + +.pinkie { + position: absolute; + width: 140px; + height: 126px; + top: 276px; + left: 64px; + background: url(gfx/pie-dash.gif); +} + +.pinkie.jumping { + background: url(gfx/pie-jump.gif) !important; +} + +.pinkie.gameover { + background: url(gfx/pie-oops.gif) !important; +} + +.ground { + position: absolute; + width: 3840px; + height: 256px; + top: 384px; + left: -128px; + background: url(gfx/map.png); + z-index: -1; +} + +.hater { + position: absolute; + width: 150px; + height: 113px; + left: -512px; + background: url(gfx/trollface.gif); +} + +.coin { + position: absolute; + width: 128px; + height: 128px; + left: -512px; + background: url(gfx/coin.gif); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.html b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.html new file mode 100644 index 0000000..938142b --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/game.html @@ -0,0 +1,54 @@ + + + + + + hai lol + + + + + + + + + + + + +
+ + + + + diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/clouds.png b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/clouds.png new file mode 100644 index 0000000..b246f3c Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/clouds.png differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/coin.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/coin.gif new file mode 100644 index 0000000..983d9c3 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/coin.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/map.png b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/map.png new file mode 100644 index 0000000..6996b4c Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/map.png differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-dash.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-dash.gif new file mode 100644 index 0000000..b3c9744 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-dash.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-jump.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-jump.gif new file mode 100644 index 0000000..5a0f437 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-jump.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-oops.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-oops.gif new file mode 100644 index 0000000..fc47683 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/pie-oops.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/trollface.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/trollface.gif new file mode 100644 index 0000000..215c146 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/gfx/trollface.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/lib/mousetrap.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/lib/mousetrap.js new file mode 100644 index 0000000..114a222 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/lib/mousetrap.js @@ -0,0 +1,9 @@ +/* mousetrap v1.4.6 craig.is/killing/mice */ +(function(J,r,f){function s(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,d;for(d in n)a[d]?b=!0:n[d]=0;b||(u=!1)}function C(a,b,d,c,e,v){var g,k,f=[],h=d.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;gg||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;c -1; +} + +var CSSCore = { + + /** + * Adds the class passed in to the element if it doesn't already have it. + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @return {DOMElement} the element passed in + */ + addClass: function(element, className) { + ("production" !== "development" ? invariant( + !/\s/.test(className), + 'CSSCore.addClass takes only a single class name. "%s" contains ' + + 'multiple classes.', className + ) : invariant(!/\s/.test(className))); + + if (className) { + if (element.classList) { + element.classList.add(className); + } else if (!hasClass(element, className)) { + element.className = element.className + ' ' + className; + } + } + return element; + }, + + /** + * Removes the class passed in from the element + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @return {DOMElement} the element passed in + */ + removeClass: function(element, className) { + ("production" !== "development" ? invariant( + !/\s/.test(className), + 'CSSCore.removeClass takes only a single class name. "%s" contains ' + + 'multiple classes.', className + ) : invariant(!/\s/.test(className))); + + if (className) { + if (element.classList) { + element.classList.remove(className); + } else if (hasClass(element, className)) { + element.className = element.className + .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1') + .replace(/\s+/g, ' ') // multiple spaces to one + .replace(/^\s*|\s*$/g, ''); // trim the ends + } + } + return element; + }, + + /** + * Helper to add or remove a class from an element based on a condition. + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @param {*} bool condition to whether to add or remove the class + * @return {DOMElement} the element passed in + */ + conditionClass: function(element, className, bool) { + return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className); + } +}; + +module.exports = CSSCore; + +},{"./invariant":109}],3:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSProperty + */ + +"use strict"; + +/** + * CSS properties which accept numbers but are not in units of "px". + */ +var isUnitlessNumber = { + fillOpacity: true, + fontWeight: true, + lineHeight: true, + opacity: true, + orphans: true, + zIndex: true, + zoom: true +}; + +/** + * Most style properties can be unset by doing .style[prop] = '' but IE8 + * doesn't like doing that with shorthand properties so for the properties that + * IE8 breaks on, which are listed here, we instead unset each of the + * individual properties. See http://bugs.jquery.com/ticket/12385. + * The 4-value 'clock' properties like margin, padding, border-width seem to + * behave without any problems. Curiously, list-style works too without any + * special prodding. + */ +var shorthandPropertyExpansions = { + background: { + backgroundImage: true, + backgroundPosition: true, + backgroundRepeat: true, + backgroundColor: true + }, + border: { + borderWidth: true, + borderStyle: true, + borderColor: true + }, + borderBottom: { + borderBottomWidth: true, + borderBottomStyle: true, + borderBottomColor: true + }, + borderLeft: { + borderLeftWidth: true, + borderLeftStyle: true, + borderLeftColor: true + }, + borderRight: { + borderRightWidth: true, + borderRightStyle: true, + borderRightColor: true + }, + borderTop: { + borderTopWidth: true, + borderTopStyle: true, + borderTopColor: true + }, + font: { + fontStyle: true, + fontVariant: true, + fontWeight: true, + fontSize: true, + lineHeight: true, + fontFamily: true + } +}; + +var CSSProperty = { + isUnitlessNumber: isUnitlessNumber, + shorthandPropertyExpansions: shorthandPropertyExpansions +}; + +module.exports = CSSProperty; + +},{}],4:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSPropertyOperations + * @typechecks static-only + */ + +"use strict"; + +var CSSProperty = require("./CSSProperty"); + +var dangerousStyleValue = require("./dangerousStyleValue"); +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var hyphenate = require("./hyphenate"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processStyleName = memoizeStringOnly(function(styleName) { + return escapeTextForBrowser(hyphenate(styleName)); +}); + +/** + * Operations for dealing with CSS properties. + */ +var CSSPropertyOperations = { + + /** + * Serializes a mapping of style properties for use as inline styles: + * + * > createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * + * @param {object} styles + * @return {?string} + */ + createMarkupForStyles: function(styles) { + var serialized = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if (styleValue != null) { + serialized += processStyleName(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue) + ';'; + } + } + return serialized || null; + }, + + /** + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles + */ + setValueForStyles: function(node, styles) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = dangerousStyleValue(styleName, styles[styleName]); + if (styleValue) { + style[styleName] = styleValue; + } else { + var expansion = CSSProperty.shorthandPropertyExpansions[styleName]; + if (expansion) { + // Shorthand property that IE8 won't like unsetting, so unset each + // component to placate it + for (var individualStyleName in expansion) { + style[individualStyleName] = ''; + } + } else { + style[styleName] = ''; + } + } + } + } + +}; + +module.exports = CSSPropertyOperations; + +},{"./CSSProperty":3,"./dangerousStyleValue":93,"./escapeTextForBrowser":95,"./hyphenate":108,"./memoizeStringOnly":117}],5:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CallbackRegistry + * @typechecks static-only + */ + +"use strict"; + +var listenerBank = {}; + +/** + * Stores "listeners" by `registrationName`/`id`. There should be at most one + * "listener" per `registrationName`/`id` in the `listenerBank`. + * + * Access listeners via `listenerBank[registrationName][id]`. + * + * @class CallbackRegistry + * @internal + */ +var CallbackRegistry = { + + /** + * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {?function} listener The callback to store. + */ + putListener: function(id, registrationName, listener) { + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, + + /** + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, + + /** + * Deletes a listener from the registration bank. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + */ + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, + + /** + * Deletes all listeners for the DOM element with the supplied ID. + * + * @param {string} id ID of the DOM element. + */ + deleteAllListeners: function(id) { + for (var registrationName in listenerBank) { + delete listenerBank[registrationName][id]; + } + }, + + /** + * This is needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + } + +}; + +module.exports = CallbackRegistry; + +},{}],6:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ChangeEventPlugin + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var SyntheticEvent = require("./SyntheticEvent"); + +var isEventSupported = require("./isEventSupported"); +var isTextInputElement = require("./isTextInputElement"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; + +var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: keyOf({onChange: null}), + captured: keyOf({onChangeCapture: null}) + } + } +}; + +/** + * For IE shims + */ +var activeElement = null; +var activeElementID = null; +var activeElementValue = null; +var activeElementValueProp = null; + +/** + * SECTION: handle `change` event + */ +function shouldUseChangeEvent(elem) { + return ( + elem.nodeName === 'SELECT' || + (elem.nodeName === 'INPUT' && elem.type === 'file') + ); +} + +var doesChangeEventBubble = false; +if (ExecutionEnvironment.canUseDOM) { + // See `handleChange` comment below + doesChangeEventBubble = isEventSupported('change') && ( + !('documentMode' in document) || document.documentMode > 8 + ); +} + +function manualDispatchChangeEvent(nativeEvent) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + activeElementID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + + // If change bubbled, we'd just bind to it like all the other events + // and have it go through ReactEventTopLevelCallback. Since it doesn't, we + // manually listen for the change event and so we have to enqueue and + // process the abstract event manually. + EventPluginHub.enqueueEvents(event); + EventPluginHub.processEventQueue(); +} + +function startWatchingForChangeEventIE8(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElement.attachEvent('onchange', manualDispatchChangeEvent); +} + +function stopWatchingForChangeEventIE8() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onchange', manualDispatchChangeEvent); + activeElement = null; + activeElementID = null; +} + +function getTargetIDForChangeEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topChange) { + return topLevelTargetID; + } +} +function handleEventsForChangeEventIE8( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForChangeEventIE8(); + startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForChangeEventIE8(); + } +} + + +/** + * SECTION: handle `input` event + */ +var isInputEventSupported = false; +if (ExecutionEnvironment.canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events + isInputEventSupported = isEventSupported('input') && ( + !('documentMode' in document) || document.documentMode > 9 + ); +} + +/** + * (For old IE.) Replacement getter/setter for the `value` property that gets + * set on the active element. + */ +var newValueProp = { + get: function() { + return activeElementValueProp.get.call(this); + }, + set: function(val) { + // Cast to a string so we can do equality checks. + activeElementValue = '' + val; + activeElementValueProp.set.call(this, val); + } +}; + +/** + * (For old IE.) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ +function startWatchingForValueChange(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElementValue = target.value; + activeElementValueProp = Object.getOwnPropertyDescriptor( + target.constructor.prototype, + 'value' + ); + + Object.defineProperty(activeElement, 'value', newValueProp); + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} + +/** + * (For old IE.) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + + // delete restores the original property definition + delete activeElement.value; + activeElement.detachEvent('onpropertychange', handlePropertyChange); + + activeElement = null; + activeElementID = null; + activeElementValue = null; + activeElementValueProp = null; +} + +/** + * (For old IE.) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== 'value') { + return; + } + var value = nativeEvent.srcElement.value; + if (value === activeElementValue) { + return; + } + activeElementValue = value; + + manualDispatchChangeEvent(nativeEvent); +} + +/** + * If a `change` event should be fired, returns the target's ID. + */ +function getTargetIDForInputEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topInput) { + // In modern browsers (i.e., not IE8 or IE9), the input event is exactly + // what we want so fall through here and trigger an abstract event + return topLevelTargetID; + } +} + +// For IE8 and IE9. +function handleEventsForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // In IE8, we can capture almost all .value changes by adding a + // propertychange handler and looking for events with propertyName + // equal to 'value' + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForValueChange(); + } +} + +// For IE8 and IE9. +function getTargetIDForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topSelectionChange || + topLevelType === topLevelTypes.topKeyUp || + topLevelType === topLevelTypes.topKeyDown) { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + if (activeElement && activeElement.value !== activeElementValue) { + activeElementValue = activeElement.value; + return activeElementID; + } + } +} + + +/** + * SECTION: handle `click` event + */ +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + return ( + elem.nodeName === 'INPUT' && + (elem.type === 'checkbox' || elem.type === 'radio') + ); +} + +function getTargetIDForClickEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topClick) { + return topLevelTargetID; + } +} + +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - select + */ +var ChangeEventPlugin = { + + eventTypes: eventTypes, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + + var getTargetIDFunc, handleEventFunc; + if (shouldUseChangeEvent(topLevelTarget)) { + if (doesChangeEventBubble) { + getTargetIDFunc = getTargetIDForChangeEvent; + } else { + handleEventFunc = handleEventsForChangeEventIE8; + } + } else if (isTextInputElement(topLevelTarget)) { + if (isInputEventSupported) { + getTargetIDFunc = getTargetIDForInputEvent; + } else { + getTargetIDFunc = getTargetIDForInputEventIE; + handleEventFunc = handleEventsForInputEventIE; + } + } else if (shouldUseClickEvent(topLevelTarget)) { + getTargetIDFunc = getTargetIDForClickEvent; + } + + if (getTargetIDFunc) { + var targetID = getTargetIDFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + if (targetID) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + targetID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + } + } + +}; + +module.exports = ChangeEventPlugin; + +},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./SyntheticEvent":76,"./isEventSupported":110,"./isTextInputElement":112,"./keyOf":116}],7:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CompositionEventPlugin + * @typechecks static-only + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactInputSelection = require("./ReactInputSelection"); +var SyntheticCompositionEvent = require("./SyntheticCompositionEvent"); + +var getTextContentAccessor = require("./getTextContentAccessor"); +var keyOf = require("./keyOf"); + +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +var START_KEYCODE = 229; + +var useCompositionEvent = ExecutionEnvironment.canUseDOM && + 'CompositionEvent' in window; +var topLevelTypes = EventConstants.topLevelTypes; +var currentComposition = null; + +// Events and their corresponding property names. +var eventTypes = { + compositionEnd: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionEnd: null}), + captured: keyOf({onCompositionEndCapture: null}) + } + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionStart: null}), + captured: keyOf({onCompositionStartCapture: null}) + } + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionUpdate: null}), + captured: keyOf({onCompositionUpdateCapture: null}) + } + } +}; + +/** + * Translate native top level events into event types. + * + * @param {string} topLevelType + * @return {object} + */ +function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case topLevelTypes.topCompositionStart: + return eventTypes.compositionStart; + case topLevelTypes.topCompositionEnd: + return eventTypes.compositionEnd; + case topLevelTypes.topCompositionUpdate: + return eventTypes.compositionUpdate; + } +} + +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackStart(topLevelType, nativeEvent) { + return ( + topLevelType === topLevelTypes.topKeyDown && + nativeEvent.keyCode === START_KEYCODE + ); +} + +/** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case topLevelTypes.topKeyUp: + // Command keys insert or clear IME input. + return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1); + case topLevelTypes.topKeyDown: + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return (nativeEvent.keyCode !== START_KEYCODE); + case topLevelTypes.topKeyPress: + case topLevelTypes.topMouseDown: + case topLevelTypes.topBlur: + // Events are not possible without cancelling IME. + return true; + default: + return false; + } +} + +/** + * Helper class stores information about selection and document state + * so we can figure out what changed at a later date. + * + * @param {DOMEventTarget} root + */ +function FallbackCompositionState(root) { + this.root = root; + this.startSelection = ReactInputSelection.getSelection(root); + this.startValue = this.getText(); +} + +/** + * Get current text of input. + * + * @return {string} + */ +FallbackCompositionState.prototype.getText = function() { + return this.root.value || this.root[getTextContentAccessor()]; +}; + +/** + * Text that has changed since the start of composition. + * + * @return {string} + */ +FallbackCompositionState.prototype.getData = function() { + var endValue = this.getText(); + var prefixLength = this.startSelection.start; + var suffixLength = this.startValue.length - this.startSelection.end; + + return endValue.substr( + prefixLength, + endValue.length - suffixLength - prefixLength + ); +}; + +/** + * This plugin creates `onCompositionStart`, `onCompositionUpdate` and + * `onCompositionEnd` events on inputs, textareas and contentEditable + * nodes. + */ +var CompositionEventPlugin = { + + eventTypes: eventTypes, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + + var eventType; + var data; + + if (useCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!currentComposition) { + if (isFallbackStart(topLevelType, nativeEvent)) { + eventType = eventTypes.start; + currentComposition = new FallbackCompositionState(topLevelTarget); + } + } else if (isFallbackEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + data = currentComposition.getData(); + currentComposition = null; + } + + if (eventType) { + var event = SyntheticCompositionEvent.getPooled( + eventType, + topLevelTargetID, + nativeEvent + ); + if (data) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = data; + } + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } +}; + +module.exports = CompositionEventPlugin; + +},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactInputSelection":50,"./SyntheticCompositionEvent":75,"./getTextContentAccessor":106,"./keyOf":116}],8:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMChildrenOperations + * @typechecks static-only + */ + +"use strict"; + +var Danger = require("./Danger"); +var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); + +var getTextContentAccessor = require("./getTextContentAccessor"); + +/** + * The DOM property to use when setting text content. + * + * @type {string} + * @private + */ +var textContentAccessor = getTextContentAccessor() || 'NA'; + +/** + * Inserts `childNode` as a child of `parentNode` at the `index`. + * + * @param {DOMElement} parentNode Parent node in which to insert. + * @param {DOMElement} childNode Child node to insert. + * @param {number} index Index at which to insert the child. + * @internal + */ +function insertChildAt(parentNode, childNode, index) { + var childNodes = parentNode.childNodes; + if (childNodes[index] === childNode) { + return; + } + // If `childNode` is already a child of `parentNode`, remove it so that + // computing `childNodes[index]` takes into account the removal. + if (childNode.parentNode === parentNode) { + parentNode.removeChild(childNode); + } + if (index >= childNodes.length) { + parentNode.appendChild(childNode); + } else { + parentNode.insertBefore(childNode, childNodes[index]); + } +} + +/** + * Operations for updating with DOM children. + */ +var DOMChildrenOperations = { + + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + + /** + * Updates a component's children by processing a series of updates. The + * update configurations are each expected to have a `parentNode` property. + * + * @param {array} updates List of update configurations. + * @param {array} markupList List of markup strings. + * @internal + */ + processUpdates: function(updates, markupList) { + var update; + // Mapping from parent IDs to initial child orderings. + var initialChildren = null; + // List of children that will be moved or removed. + var updatedChildren = null; + + for (var i = 0; update = updates[i]; i++) { + if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || + update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { + var updatedIndex = update.fromIndex; + var updatedChild = update.parentNode.childNodes[updatedIndex]; + var parentID = update.parentID; + + initialChildren = initialChildren || {}; + initialChildren[parentID] = initialChildren[parentID] || []; + initialChildren[parentID][updatedIndex] = updatedChild; + + updatedChildren = updatedChildren || []; + updatedChildren.push(updatedChild); + } + } + + var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + + // Remove updated children first so that `toIndex` is consistent. + if (updatedChildren) { + for (var j = 0; j < updatedChildren.length; j++) { + updatedChildren[j].parentNode.removeChild(updatedChildren[j]); + } + } + + for (var k = 0; update = updates[k]; k++) { + switch (update.type) { + case ReactMultiChildUpdateTypes.INSERT_MARKUP: + insertChildAt( + update.parentNode, + renderedMarkup[update.markupIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.MOVE_EXISTING: + insertChildAt( + update.parentNode, + initialChildren[update.parentID][update.fromIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.TEXT_CONTENT: + update.parentNode[textContentAccessor] = update.textContent; + break; + case ReactMultiChildUpdateTypes.REMOVE_NODE: + // Already removed by the for-loop above. + break; + } + } + } + +}; + +module.exports = DOMChildrenOperations; + +},{"./Danger":11,"./ReactMultiChildUpdateTypes":57,"./getTextContentAccessor":106}],9:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMProperty + * @typechecks static-only + */ + +/*jslint bitwise: true */ + +"use strict"; + +var invariant = require("./invariant"); + +var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_ATTRIBUTE: 0x1, + MUST_USE_PROPERTY: 0x2, + HAS_SIDE_EFFECTS: 0x4, + HAS_BOOLEAN_VALUE: 0x8, + HAS_POSITIVE_NUMERIC_VALUE: 0x10, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function(domPropertyConfig) { + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push( + domPropertyConfig.isCustomAttribute + ); + } + + for (var propName in Properties) { + ("production" !== "development" ? invariant( + !DOMProperty.isStandardName[propName], + 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + + '\'%s\' which has already been injected. You may be accidentally ' + + 'injecting the same DOM property config twice, or you may be ' + + 'injecting two configs that have conflicting property names.', + propName + ) : invariant(!DOMProperty.isStandardName[propName])); + + DOMProperty.isStandardName[propName] = true; + + var lowerCased = propName.toLowerCase(); + DOMProperty.getPossibleStandardName[lowerCased] = propName; + + var attributeName = DOMAttributeNames[propName]; + if (attributeName) { + DOMProperty.getPossibleStandardName[attributeName] = propName; + } + + DOMProperty.getAttributeName[propName] = attributeName || lowerCased; + + DOMProperty.getPropertyName[propName] = + DOMPropertyNames[propName] || propName; + + var mutationMethod = DOMMutationMethods[propName]; + if (mutationMethod) { + DOMProperty.getMutationMethod[propName] = mutationMethod; + } + + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = + propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE; + DOMProperty.mustUseProperty[propName] = + propConfig & DOMPropertyInjection.MUST_USE_PROPERTY; + DOMProperty.hasSideEffects[propName] = + propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS; + DOMProperty.hasBooleanValue[propName] = + propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE; + DOMProperty.hasPositiveNumericValue[propName] = + propConfig & DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE; + + ("production" !== "development" ? invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot require using both attribute and property: %s', + propName + ) : invariant(!DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName])); + ("production" !== "development" ? invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ) : invariant(DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName])); + ("production" !== "development" ? invariant( + !DOMProperty.hasBooleanValue[propName] || + !DOMProperty.hasPositiveNumericValue[propName], + 'DOMProperty: Cannot have both boolean and positive numeric value: %s', + propName + ) : invariant(!DOMProperty.hasBooleanValue[propName] || + !DOMProperty.hasPositiveNumericValue[propName])); + } + } +}; +var defaultValueCache = {}; + +/** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ +var DOMProperty = { + + /** + * Checks whether a property name is a standard property. + * @type {Object} + */ + isStandardName: {}, + + /** + * Mapping from lowercase property names to the properly cased version, used + * to warn in the case of missing properties. + * @type {Object} + */ + getPossibleStandardName: {}, + + /** + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} + */ + getAttributeName: {}, + + /** + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} + */ + getPropertyName: {}, + + /** + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} + */ + getMutationMethod: {}, + + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, + + /** + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} + */ + mustUseProperty: {}, + + /** + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. We must ensure that + * the value is only set if it has changed. + * @type {Object} + */ + hasSideEffects: {}, + + /** + * Whether the property should be removed when set to a falsey value. + * @type {Object} + */ + hasBooleanValue: {}, + + /** + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * @type {Object} + */ + hasPositiveNumericValue: {}, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function(attributeName) { + return DOMProperty._isCustomAttributeFunctions.some( + function(isCustomAttributeFn) { + return isCustomAttributeFn.call(null, attributeName); + } + ); + }, + + /** + * Returns the default property value for a DOM property (i.e., not an + * attribute). Most default values are '' or false, but not all. Worse yet, + * some (in particular, `type`) vary depending on the type of element. + * + * TODO: Is it better to grab all the possible properties when creating an + * element to avoid having to create the same element twice? + */ + getDefaultValueForProperty: function(nodeName, prop) { + var nodeDefaults = defaultValueCache[nodeName]; + var testElement; + if (!nodeDefaults) { + defaultValueCache[nodeName] = nodeDefaults = {}; + } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + + injection: DOMPropertyInjection +}; + +module.exports = DOMProperty; + +},{"./invariant":109}],10:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMPropertyOperations + * @typechecks static-only + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +function shouldIgnoreValue(name, value) { + return value == null || + DOMProperty.hasBooleanValue[name] && !value || + DOMProperty.hasPositiveNumericValue[name] && (isNaN(value) || value < 1); +} + +var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { + return escapeTextForBrowser(name) + '="'; +}); + +if ("production" !== "development") { + var reactProps = { + __owner__: true, + children: true, + dangerouslySetInnerHTML: true, + key: true, + ref: true + }; + var warnedProperties = {}; + + var warnUnknownProperty = function(name) { + if (reactProps[name] || warnedProperties[name]) { + return; + } + + warnedProperties[name] = true; + var lowerCasedName = name.toLowerCase(); + + // data-* attributes should be lowercase; suggest the lowercase version + var standardName = DOMProperty.isCustomAttribute(lowerCasedName) ? + lowerCasedName : DOMProperty.getPossibleStandardName[lowerCasedName]; + + // For now, only warn when we have a suggested correction. This prevents + // logging too much when using transferPropsTo. + if (standardName != null) { + console.warn( + 'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?' + ); + } + + }; +} + +/** + * Operations for dealing with DOM properties. + */ +var DOMPropertyOperations = { + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName[name]) { + if (shouldIgnoreValue(name, value)) { + return ''; + } + var attributeName = DOMProperty.getAttributeName[name]; + return processAttributeNameAndPrefix(attributeName) + + escapeTextForBrowser(value) + '"'; + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return processAttributeNameAndPrefix(name) + + escapeTextForBrowser(value) + '"'; + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + return null; + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function(node, name, value) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, value); + } else if (shouldIgnoreValue(name, value)) { + this.deleteValueForProperty(node, name); + } else if (DOMProperty.mustUseAttribute[name]) { + node.setAttribute(DOMProperty.getAttributeName[name], '' + value); + } else { + var propName = DOMProperty.getPropertyName[name]; + if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + node.setAttribute(name, '' + value); + } + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + }, + + /** + * Deletes the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + */ + deleteValueForProperty: function(node, name) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, undefined); + } else if (DOMProperty.mustUseAttribute[name]) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + var propName = DOMProperty.getPropertyName[name]; + var defaultValue = DOMProperty.getDefaultValueForProperty( + node.nodeName, + name + ); + if (!DOMProperty.hasSideEffects[name] || + node[propName] !== defaultValue) { + node[propName] = defaultValue; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + } + +}; + +module.exports = DOMPropertyOperations; + +},{"./DOMProperty":9,"./escapeTextForBrowser":95,"./memoizeStringOnly":117}],11:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule Danger + * @typechecks static-only + */ + +/*jslint evil: true, sub: true */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var createNodesFromMarkup = require("./createNodesFromMarkup"); +var emptyFunction = require("./emptyFunction"); +var getMarkupWrap = require("./getMarkupWrap"); +var invariant = require("./invariant"); +var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); + +var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; +var RESULT_INDEX_ATTR = 'data-danger-index'; + +/** + * Extracts the `nodeName` from a string of markup. + * + * NOTE: Extracting the `nodeName` does not require a regular expression match + * because we make assumptions about React-generated markup (i.e. there are no + * spaces surrounding the opening tag and there is at least one attribute). + * + * @param {string} markup String of markup. + * @return {string} Node name of the supplied markup. + * @see http://jsperf.com/extract-nodename + */ +function getNodeName(markup) { + return markup.substring(1, markup.indexOf(' ')); +} + +var Danger = { + + /** + * Renders markup into an array of nodes. The markup is expected to render + * into a list of root nodes. Also, the length of `resultList` and + * `markupList` should be the same. + * + * @param {array} markupList List of markup strings to render. + * @return {array} List of rendered nodes. + * @internal + */ + dangerouslyRenderMarkup: function(markupList) { + ("production" !== "development" ? invariant( + ExecutionEnvironment.canUseDOM, + 'dangerouslyRenderMarkup(...): Cannot render markup in a Worker ' + + 'thread. This is likely a bug in the framework. Please report ' + + 'immediately.' + ) : invariant(ExecutionEnvironment.canUseDOM)); + var nodeName; + var markupByNodeName = {}; + // Group markup by `nodeName` if a wrap is necessary, else by '*'. + for (var i = 0; i < markupList.length; i++) { + ("production" !== "development" ? invariant( + markupList[i], + 'dangerouslyRenderMarkup(...): Missing markup.' + ) : invariant(markupList[i])); + nodeName = getNodeName(markupList[i]); + nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; + markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; + markupByNodeName[nodeName][i] = markupList[i]; + } + var resultList = []; + var resultListAssignmentCount = 0; + for (nodeName in markupByNodeName) { + if (!markupByNodeName.hasOwnProperty(nodeName)) { + continue; + } + var markupListByNodeName = markupByNodeName[nodeName]; + + // This for-in loop skips the holes of the sparse array. The order of + // iteration should follow the order of assignment, which happens to match + // numerical index order, but we don't rely on that. + for (var resultIndex in markupListByNodeName) { + if (markupListByNodeName.hasOwnProperty(resultIndex)) { + var markup = markupListByNodeName[resultIndex]; + + // Push the requested markup with an additional RESULT_INDEX_ATTR + // attribute. If the markup does not start with a < character, it + // will be discarded below (with an appropriate console.error). + markupListByNodeName[resultIndex] = markup.replace( + OPEN_TAG_NAME_EXP, + // This index will be parsed back out below. + '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" ' + ); + } + } + + // Render each group of markup with similar wrapping `nodeName`. + var renderNodes = createNodesFromMarkup( + markupListByNodeName.join(''), + emptyFunction // Do nothing special with + + + + + + + +
+
+
+
+ + + + + diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/coin.mp3 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/coin.mp3 new file mode 100644 index 0000000..89dad7c Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/coin.mp3 differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/gameover.mp3 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/gameover.mp3 new file mode 100644 index 0000000..fef4897 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/gameover.mp3 differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/jump.mp3 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/jump.mp3 new file mode 100644 index 0000000..8a3c0be Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/jump.mp3 differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/smile.mp3 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/smile.mp3 new file mode 100644 index 0000000..3bdddbd Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/game/sfx/smile.mp3 differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/index.html b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/index.html new file mode 100644 index 0000000..93fe7b0 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/index.html @@ -0,0 +1,309 @@ + + + + + + + + Reactive Game Development For The Discerning Hipster + + + + + + + + + + + + + + +
+ +
+

REACTIVE GAME DEVELOPMENT

+

for the

+

DISCERNING HIPSTER

+

@bodil

+
+ +
+
+ +
+
kleisli arrows
+
yoneda lemma
+
cofree coburritos
+
zygohistomorphic prepromorphisms
+
+ +
+

FUNCTIONAL REACTIVE PROGRAMMING

+

NOW!

+
+ +
+

Reactive Extensions

+
+ +
+

RxJS

+
+ +
+

React.JS

+
+ +
+ var ponies = Rx.Observable.fromArray([ + "Fluttershy", + "Twilight Sparkle", + "Applejack", + "Rarity", + "Rainbow Dash", + "Pinkie Pie" + ]); +
+ +
+ var ponies = Rx.Observable.fromArray([ + "Fluttershy", + "Twilight Sparkle", + "Applejack", + "Rarity", + "Rainbow Dash", + "Pinkie Pie" + ]); + + var ponyTime = Rx.Observable.zip( + Rx.Observable.interval(500), + ponies, (tick, i) => i + ).log(); + + // ponyTime + // .filter((pony) => /e$/.test(pony)) + // .map((pony) => "I love " + pony) + // .log(); +
+ +
+const canvas = document.getElementById("canvas"); + +function extend(target, obj) { + for (let prop in obj) target[prop] = obj[prop]; +} + +function assoc() { + let out = {}; + for (let i = 0; i < arguments.length; i++) + extend(out, arguments[i]); + return out; +} + +function onscreen(node) { + return !(node.x < -300 || node.y < -1000 || node.y > 1000); +} + +function bindKey(key) { + let sub = new Rx.Subject(); + Mousetrap.bind(key, () => { + sub.onNext(key); + }); + return sub; +} +
+ +
+const canvas = document.getElementById("canvas"); + +function extend(target, obj) { + for (let prop in obj) target[prop] = obj[prop]; +} + +function assoc() { + let out = {}; + for (let i = 0; i < arguments.length; i++) + extend(out, arguments[i]); + return out; +} + +function onscreen(node) { + return !(node.x < -300 || node.y < -1000 || node.y > 1000); +} + +function bindKey(key) { + let sub = new Rx.Subject(); + Mousetrap.bind(key, () => { + sub.onNext(key); + }); + return sub; +} + +function makeElement(node) { + return React.DOM.div({ + className: node.id, + style: { + left: (node.x + (node.baseX || 0)) | 0 + "px", + top: (node.y + (node.baseY || 0)) | 0 + "px" + } + }); +} + +function renderScene(nodes) { + return React.renderComponent( + React.DOM.div(null, nodes.map(makeElement)), + canvas + ); +} + +let groundStream = Rx.Observable.interval(33) + .map((x) => ({ + id: "ground", + baseX: -128, + x: ((x % 64) * -8), y: 384 + })); + +function velocity(node) { + return assoc(node, { + x: node.x + node.vx, + y: node.y + node.vy + }); +} + +let tick = bindKey("space") + .buffer(Rx.Observable.interval(33)); + +let initialHater = { + id: "hater", + vx: -8, vy: 0, + x: 1600, y: 300 +}; + +let haterStream = tick.scan(initialHater, (c, keys) => { + // Apply velocity to position. + c = velocity(c); + return onscreen(c) ? c : initialHater; +}); + +let pinkieStream = Rx.Observable.zipArray(tick, haterStream).scan({ + id: "pinkie", + baseY: 276, + x: 0, y: 0, + vx: 0, vy: 0, + gameOver: false +}, (p, [keys, hater]) => { + p = velocity(p); + + if (intersects(p, hater) && !p.gameOver) { + p.gameOver = true; + p.id = "pinkie gameover"; + new Audio("sfx/gameover.mp3").play(); + p.vy = -15; + } + if (p.gameOver) { + p.vy += 0.5; + return p; + } + + // Apply gravity to Pinkie's velocity. + p.vy += 0.98; + + // AS Pinkie Pie, + // GIVEN that I'm falling + // WHEN I hit the ground + // THEN I stop. + if (p.y >= 0 && p.vy > 0) { + p.y = 0; p.vy = 0; + } + + // If Pinkie is on the ground and space has been pressed, JUMP. + if (keys[0] === "space") { + // p.vy = -20; // wheeee infinite jump + if (p.y === 0) { + p.vy = -20; + new Audio("sfx/jump.mp3").play(); + } + } + + p.id = (p.y < 0) ? "pinkie jumping" : "pinkie"; + + return p; +}).takeWhile(onscreen); + +let initialCoin = { + id: "coin", + vx: -6, vy: 0, + x: 1600, y: 40 +}; + +let coinStream = pinkieStream.scan(initialCoin, (c, pinkie) => { + // Apply velocity to position. + c = velocity(c); + + // If Pinkie touches the coin, ding it! + if (c.vy === 0 && intersects(c, pinkie)) { + new Audio("sfx/coin.mp3").play(); + c.vx = 0; c.vy = -1; + } + if (c.vy < 0) { + c.vy = c.vy * 2; + } + + return onscreen(c) ? c : initialCoin; +}); + +Rx.Observable.zipArray(pinkieStream, groundStream, coinStream, haterStream) + .subscribe(renderScene); +
+ +
+

RxJS

+

http://reactive-extensions.github.io/RxJS/

+
+ +
+

Bacon.js

+

http://baconjs.github.io/

+
+ +
+

Elm

+

http://elm-lang.org/

+
+ +
+ +

Thank you!

+ +

@bodil

+

+ bodil.org/boogaloo/ +

+
+
+ + + +
+
+
+ +
+

QUESTIONS?

+
+ +
+ + + + + diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/bad-doge.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/bad-doge.jpg new file mode 100644 index 0000000..c524e6c Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/bad-doge.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/beard-off.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/beard-off.jpg new file mode 100644 index 0000000..5602122 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/beard-off.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-racer.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-racer.jpg new file mode 100644 index 0000000..584a6b4 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-racer.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-sees-all.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-sees-all.jpg new file mode 100644 index 0000000..dbed2fe Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh-sees-all.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh.jpg new file mode 100644 index 0000000..eaab85c Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/dhh.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/doge.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/doge.gif new file mode 100644 index 0000000..db3fcbe Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/doge.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/erik.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/erik.jpg new file mode 100644 index 0000000..2e60881 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/erik.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/glasses.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/glasses.jpg new file mode 100644 index 0000000..a80a4ff Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/glasses.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/have-fixie-will-hip.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/have-fixie-will-hip.jpg new file mode 100644 index 0000000..80774fd Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/have-fixie-will-hip.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/hipster-pinkie.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/hipster-pinkie.jpg new file mode 100644 index 0000000..889ab5b Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/hipster-pinkie.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/joe.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/joe.jpg new file mode 100644 index 0000000..f5e2166 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/joe.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/mad-doge.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/mad-doge.jpg new file mode 100644 index 0000000..48099a9 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/mad-doge.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/moby-dick.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/moby-dick.jpg new file mode 100644 index 0000000..f7d9249 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/moby-dick.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/muchmine.gif b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/muchmine.gif new file mode 100644 index 0000000..8482a46 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/muchmine.gif differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/party-cannon-3.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/party-cannon-3.jpg new file mode 100644 index 0000000..62764a2 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/party-cannon-3.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/splash.png b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/splash.png new file mode 100644 index 0000000..8f478cc Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/splash.png differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/steve.jpg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/steve.jpg new file mode 100644 index 0000000..ee402a8 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/steve.jpg differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/such-pinkie.png b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/such-pinkie.png new file mode 100644 index 0000000..21c71c9 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/m/such-pinkie.png differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/notes.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/notes.js new file mode 100644 index 0000000..305454c --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/notes.js @@ -0,0 +1,117 @@ +// --- Actual game: + +function makeElement(node) { + return React.DOM.div({ + className: node.id, + style: { + left: (node.x + (node.baseX || 0)) | 0 + "px", + top: (node.y + (node.baseY || 0)) | 0 + "px" + } + }); +} + +function renderScene(nodes) { + return React.renderComponent( + React.DOM.div(null, nodes.map(makeElement)), + canvas + ); +} + +let groundStream = Rx.Observable.interval(33) + .map((x) => ({ + id: "ground", + baseX: -128, + x: ((x % 64) * -8), y: 384 + })); + +function velocity(node) { + return assoc(node, { + x: node.x + node.vx, + y: node.y + node.vy + }); +} + +let tick = bindKey("space") + .buffer(Rx.Observable.interval(33)); + +let initialHater = { + id: "hater", + vx: -8, vy: 0, + x: 1600, y: 300 +}; + +let haterStream = tick.scan(initialHater, (c, keys) => { + // Apply velocity to position. + c = velocity(c); + return onscreen(c) ? c : initialHater; +}); + +let pinkieStream = Rx.Observable.zipArray(tick, haterStream).scan({ + id: "pinkie", + baseY: 276, + x: 0, y: 0, + vx: 0, vy: 0, + gameOver: false +}, (p, [keys, hater]) => { + p = velocity(p); + + if (intersects(p, hater) && !p.gameOver) { + p.gameOver = true; + p.id = "pinkie gameover"; + new Audio("sfx/gameover.mp3").play(); + p.vy = -15; + } + if (p.gameOver) { + p.vy += 0.5; + return p; + } + + // Apply gravity to Pinkie's velocity. + p.vy += 0.98; + + // AS Pinkie Pie, + // GIVEN that I'm falling + // WHEN I hit the ground + // THEN I stop. + if (p.y >= 0 && p.vy > 0) { + p.y = 0; p.vy = 0; + } + + // If Pinkie is on the ground and space has been pressed, JUMP. + if (keys[0] === "space") { + // p.vy = -20; // wheeee infinite jump + if (p.y === 0) { + p.vy = -20; + new Audio("sfx/jump.mp3").play(); + } + } + + p.id = (p.y < 0) ? "pinkie jumping" : "pinkie"; + + return p; +}).takeWhile(onscreen); + +let initialCoin = { + id: "coin", + vx: -6, vy: 0, + x: 1600, y: 40 +}; + +let coinStream = pinkieStream.scan(initialCoin, (c, pinkie) => { + // Apply velocity to position. + c = velocity(c); + + // If Pinkie touches the coin, ding it! + if (c.vy === 0 && intersects(c, pinkie)) { + new Audio("sfx/coin.mp3").play(); + c.vx = 0; c.vy = -1; + } + if (c.vy < 0) { + c.vy = c.vy * 2; + } + + return onscreen(c) ? c : initialCoin; +}); + +Rx.Observable.zipArray(pinkieStream, groundStream, coinStream, haterStream) + .subscribe(renderScene); diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/package.json b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/package.json new file mode 100644 index 0000000..1e93577 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/package.json @@ -0,0 +1,37 @@ +{ + "name": "boogaloo", + "version": "0.0.1", + "description": "A slide deck", + "homepage": "https://github.com/bodil/boogaloo", + "author": "Bodil Stokke", + "licenses": [ + "GPL-3", + "MIT" + ], + "repository": { + "type": "git", + "url": "https://github.com/bodil/boogaloo.git" + }, + "scripts": { + "webpack": "webpack --config config/webpack.config.js --colors --progress", + "install": "npm run webpack", + "start": "webpack-dev-server --config config/webpack.config.js --port 1337" + }, + "devDependencies": { + "webpack": "~1.0.5", + "webpack-dev-server": "~1.2.3", + "less-loader": "~0.7.1", + "css-loader": "~0.6.8", + "style-loader": "~0.6.3", + "url-loader": "~0.5.3", + "json-loader": "~0.5.0", + "raw-loader": "~0.5.1" + }, + "dependencies": { + "traceur": "~0.0.25", + "codemirror": "~3.22.0", + "spin.js": "~1.3.2", + "tern": "~0.5.0", + "underscore": "~1.6.0" + } +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/doge.svg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/doge.svg new file mode 100644 index 0000000..7bba791 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/doge.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.css new file mode 100644 index 0000000..d67681f --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.css @@ -0,0 +1,6 @@ +@font-face { + font-family: 'Dijkstra'; + font-style: normal; + font-weight: 400; + src: local('Dijkstra'), url(dijkstra.ttf) format('truetype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.ttf new file mode 100644 index 0000000..84d36f2 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Dijkstra/dijkstra.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Bd.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Bd.otf new file mode 100644 index 0000000..d4ac7c1 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Bd.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-BdIt.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-BdIt.otf new file mode 100644 index 0000000..64d99f9 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-BdIt.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Lt.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Lt.otf new file mode 100644 index 0000000..1b27e9f Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Lt.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-LtIt.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-LtIt.otf new file mode 100644 index 0000000..4d0f29f Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-LtIt.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Md.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Md.otf new file mode 100644 index 0000000..0822254 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-Md.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-MdIt.otf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-MdIt.otf new file mode 100644 index 0000000..5f9ee8a Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/HelveticaNeueLTStd-MdIt.otf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/helvetica.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/helvetica.css new file mode 100644 index 0000000..1e20ce0 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Helvetica/helvetica.css @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Helvetica Neue LT Std'; + font-style: normal; + font-weight: 400; + src: local('Helvetica Neue LT Std Regular'), url(HelveticaNeueLTStd-Md.otf) format('opentype'); +} +@font-face { + font-family: 'Helvetica Neue LT Std'; + font-style: normal; + font-weight: 700; + src: local('Helvetica Neue LT Std Bold'), url(HelveticaNeueLTStd-Bd.otf) format('opentype'); +} +@font-face { + font-family: 'Helvetica Neue LT Std'; + font-style: italic; + font-weight: 400; + src: local('Helvetica Neue LT Std Regular Italic'), url(HelveticaNeueLTStd-MdIt.otf) format('opentype'); +} +@font-face { + font-family: 'Helvetica Neue LT Std'; + font-style: italic; + font-weight: 700; + src: local('Helvetica Neue LT Std Bold Italic'), url(HelveticaNeueLTStd-BdIt.otf) format('opentype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Bold.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Bold.ttf new file mode 100644 index 0000000..15eb599 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Bold.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Regular.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Regular.ttf new file mode 100644 index 0000000..4ea3681 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/Inconsolata-Regular.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/OFL.txt b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/OFL.txt new file mode 100644 index 0000000..91ed598 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/OFL.txt @@ -0,0 +1,92 @@ +Copyright (c) 2011, Raph Levien (firstname.lastname@gmail.com), Copyright (c) 2012, Cyreal (cyreal.org) +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/inconsolata.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/inconsolata.css new file mode 100644 index 0000000..ee664c0 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Inconsolata/inconsolata.css @@ -0,0 +1,12 @@ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + src: local('Inconsolata'), url(Inconsolata-Regular.ttf) format('truetype'); +} +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 700; + src: local('Inconsolata Bold'), local('Inconsolata-Bold'), url(Inconsolata-Bold.ttf) format('truetype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/LICENSE.txt b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/LICENSE.txt new file mode 100644 index 0000000..75b5248 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Bold.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Bold.ttf new file mode 100644 index 0000000..df5d1df Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Bold.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Light.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Light.ttf new file mode 100644 index 0000000..ccb99cd Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Light.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Regular.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Regular.ttf new file mode 100644 index 0000000..eb52a79 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Regular.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Thin.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Thin.ttf new file mode 100644 index 0000000..fee11da Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/RobotoSlab-Thin.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/robotoslab.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/robotoslab.css new file mode 100644 index 0000000..bcdfbad --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Roboto_Slab/robotoslab.css @@ -0,0 +1,18 @@ +@font-face { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: 300; + src: local('Roboto Slab Light'), local('RobotoSlab-Light'), url(RobotoSlab-Light.ttf) format('truetype'); +} +@font-face { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: 400; + src: local('Roboto Slab Regular'), local('RobotoSlab-Regular'), url(RobotoSlab-Regular.ttf) format('truetype'); +} +@font-face { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: 700; + src: local('Roboto Slab Bold'), local('RobotoSlab-Bold'), url(RobotoSlab-Bold.ttf) format('truetype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/OFL.txt b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/OFL.txt new file mode 100644 index 0000000..5bf4d6a --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2011 by Anna GiedryÅ› (http://ancymonic.com), +with Reserved Font Names "Signika". +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Bold.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Bold.ttf new file mode 100644 index 0000000..9cd28cf Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Bold.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Light.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Light.ttf new file mode 100644 index 0000000..7fa6e24 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Light.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Regular.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Regular.ttf new file mode 100644 index 0000000..5845c93 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Regular.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Semibold.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Semibold.ttf new file mode 100644 index 0000000..81771c0 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/Signika-Semibold.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/signika.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/signika.css new file mode 100644 index 0000000..e949de6 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/Signika/signika.css @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Signika'; + font-style: normal; + font-weight: 300; + src: local('Signika-Light'), url(Signika-Light.ttf) format('truetype'); +} +@font-face { + font-family: 'Signika'; + font-style: normal; + font-weight: 400; + src: local('Signika'), local('Signika-Regular'), url(Signika-Regular.ttf) format('truetype'); +} +@font-face { + font-family: 'Signika'; + font-style: normal; + font-weight: 600; + src: local('Signika-Semibold'), url(Signika-Semibold.ttf) format('truetype'); +} +@font-face { + font-family: 'Signika'; + font-style: normal; + font-weight: 700; + src: local('Signika-Bold'), url(Signika-Bold.ttf) format('truetype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/st-andrew.ttf b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/st-andrew.ttf new file mode 100644 index 0000000..1f59341 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/st-andrew.ttf differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/standrew.css b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/standrew.css new file mode 100644 index 0000000..1f3f91c --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/fonts/StAndrew/standrew.css @@ -0,0 +1,6 @@ +@font-face { + font-family: 'StAndrew'; + font-style: normal; + font-weight: 400; + src: local('StAndrew'), url(st-andrew.ttf) format('truetype'); +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/red-doge.svg b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/red-doge.svg new file mode 100644 index 0000000..fb389a3 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/red-doge.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/reset.less b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/reset.less new file mode 100644 index 0000000..24b6d8c --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/reset.less @@ -0,0 +1,60 @@ +/** + * Global Reset of all HTML Elements + * + * Resetting all of our HTML Elements ensures a smoother + * visual transition between browsers. If you don't believe me, + * try temporarily commenting out this block of code, then go + * and look at Mozilla versus Safari, both good browsers with + * a good implementation of CSS. The thing is, all browser CSS + * defaults are different and at the end of the day if visual + * consistency is what we're shooting for, then we need to + * make sure we're resetting all spacing elements. + * + */ +html, body { + border: 0; + font-family: "Helvetica-Neue", "Helvetica", Arial, sans-serif; + line-height: 1.5; + margin: 0; + padding: 0; +} + +div, span, object, iframe, img, table, caption, thead, tbody, +tfoot, tr, tr, td, article, aside, canvas, details, figure, hgroup, menu, +nav, footer, header, section, summary, mark, audio, video { + border: 0; + margin: 0; + padding: 0; +} + +h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, address, cit, code, +del, dfn, em, ins, q, samp, small, strong, sub, sup, b, i, hr, dl, dt, dd, +ol, ul, li, fieldset, legend, label { + border: 0; + font-size: 100%; + vertical-align: baseline; + margin: 0; + padding: 0; +} + +article, aside, canvas, figure, figure img, figcaption, hgroup, +footer, header, nav, section, audio, video { + display: block; +} + +table { + border-collapse: separate; + border-spacing: 0; + caption, th, td { + text-align: left; + vertical-align: middle; + } +} + +a img { + border: 0; +} + +:focus { + outline: 0; +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/screen.less b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/screen.less new file mode 100644 index 0000000..2d41a25 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/css/screen.less @@ -0,0 +1,306 @@ +@import "./reset.less"; +@import "./fonts/Helvetica/helvetica.css"; +@import "./fonts/Inconsolata/inconsolata.css"; + +*, *:before, *:after { + /* OMG YES YOU CAN UNBREAK THE BOX MODEL <3 <3 <3 <3 <3 <3 */ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + color: #222; + margin: 0; + padding: 0; + border: 0; + font-family: "Helvetica Neue LT Std"; + font-size: 48pt; + line-height: 1.2em; + visibility: visible; +} + +p, a, li, li:before, h1, h2, h3, h4, h5, h6 { + text-shadow: 0 0 0.1em rgba(0,0,0,0.5); +} + +h1, h2, h3, h4, h5, h6 { + text-align: center; + font-weight: bold; + background-color: rgba(0,0,0,0.1); + margin: 0.4em -100%; +} + +h1 { + font-size: 1.6em; + padding-top: 0.25em; +} + +h2 { + font-size: 1.4em; + padding-top: 0.3em; +} + +h3 { + font-size: 1.2em; + padding-top: 0.3em; +} + +h4, h5, h6 { + font-size: 1.1em; + padding-top: 0.3em; +} + +ul, ol { + li { + list-style: none; + position: relative; + + &:before { + color: #888; + text-align: right; + position: absolute; + left: 0; + } + } +} + +ul { + li:before { + content: ' '; + width: 1em; + height: 1em; + margin-left: -1em; + background: url(doge.svg); + background-size: contain; + } +} + +strong { + letter-spacing: 0.05em; +} + +a { + color: black; +} + +.attribution { + font-size: 0.9em; +} + +#slides { + z-index: 1; + position: fixed; + background: #ccc; +} + +#slides, #slides .background { + background-size: cover; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: 0; +} + +#slides .background { + z-index: 2; + position: absolute; + opacity: 0; + -webkit-transition: opacity 0.3s ease; + -moz-transition: opacity 0.3s ease; + transition: opacity 0.3s ease; + + &.active { + opacity: 1; + } +} + +#slides section { + background-color: rgba(255, 255, 255, 0.8); + background-size: cover; + background-position: 50% 50%; + + z-index: 10; + visibility: hidden; + position: absolute; + width: 80%; + height: 80%; + left: 10%; + top: 10%; + margin: 0; + padding: 0 10%; + border: 0; + border-radius: 0.2em; + + display: -webkit-box; + display: -moz-box; + display: box; + -webkit-box-pack: center; + -webkit-box-align: center; + -moz-box-pack: center; + -moz-box-align: center; + box-pack: center; + box-align: center; + + opacity: 0; + -webkit-transform: scale(1.25); + -webkit-filter: grayscale(100%); + -webkit-transition: -webkit-filter 0.3s ease, -webkit-transform 0.3s ease, opacity 0.3s ease; + -moz-transform: scale(1.25); + -moz-filter: grayscale(100%); + -moz-transition: -moz-filter 0.3s ease, -moz-transform 0.3s ease, opacity 0.3s ease; + transform: scale(1.25); + filter: grayscale(100%); + transition: filter 0.3s ease, transform 0.3s ease, opacity 0.3s ease; + + .slideContainer { + width: 100%; + } + + &.current, &.out { + visibility: visible; + } + + &.current { + opacity: 1; + -webkit-filter: grayscale(0); + -webkit-transform: scale(1); + -moz-filter: grayscale(0); + -moz-transform: scale(1); + filter: grayscale(0); + transform: scale(1); + } + + &.out { + -webkit-transform: scale(0.75); + -moz-transform: scale(0.75); + transform: scale(0.75); + } + + &.editor { + left: 0; + top: 0; + width: 100%; + height: 100%; + border-radius: 0; + background: none; + + .editorFrame, .targetFrame { + position: absolute; + width: 50%; + height: 100%; + top: 0; + padding: 0.5em; + } + + .editorFrame { + left: 0; + padding-right: 0; + } + + .targetFrame { + left: 50%; + } + + .targetFrame iframe { + z-index: 14; + background-color: #444; + background-image: url(doge.svg); + background-size: contain; + background-repeat: no-repeat; + background-position: 50% 50%; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + } + + .loaderFrame { + z-index: 15; + background: #444; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + } + + .CodeMirror { + font-family: "Inconsolata"; + line-height: 1.2em; + font-size: 0.5em; + + } + + .CodeMirror, .loaderFrame, .targetFrame iframe { + box-shadow: 0 0.1em 0.2em rgba(0, 0, 0, 0.6); + border-radius: 0.1em; + } + } + + &.photo { + background-size: contain; + background-color: rgba(0,0,0,0); + background-repeat: no-repeat; + } + + &.white { + text-align: center; + + h1, h2, h3, h4, h5, h6, p, a { + color: white; + text-shadow: 0 -0.05em 0.1em black, 0 0.05em 0.1em black, 0 0.1em 0.3em black; + background: none; + font-weight: normal; + } + } + + &.align-bottom { + -webkit-box-pack: end; + -webkit-box-align: end; + -moz-box-pack: end; + -moz-box-align: end; + box-pack: end; + box-align: end; + padding-bottom: 0.5em; + } + + &.erlang-the-movie { + h1, h2, h3, h4, h5, h6, p, a { + font-weight: bolder; + -webkit-transform: scale(0.8, 1); + -moz-transform: scale(0.8, 1); + transform: scale(0.8, 1); + margin: 0; + } + p { + font-size: 0.9em; + margin: 0 -6em; + } + } +} + +/* CodeMirror extras for the editor plugin */ + +.CodeMirror-hints, +.CodeMirror-Tern-tooltip { + font-family: "Inconsolata"; + line-height: 1.2em; + font-size: 0.5em !important; + text-shadow: none; + + & li { + text-shadow: none; + } +} + +.cm-errors { + width: 1em; +} + +.cm-error { + width: 1em; + height: 1em; + background: url(red-doge.svg); + background-size: contain; +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/deck.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/deck.es6 new file mode 100644 index 0000000..fb8a623 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/deck.es6 @@ -0,0 +1,128 @@ +/*global setTimeout */ + +var events = require("./lib/events"); +var mousetrap = require("./lib/mousetrap"); + +function toArray(indexable) { + const out = [], l = indexable.length; + for (let i = 0; i < l; i++) { + out.push(indexable[i]); + } + return out; +} + +function Deck(container, deckModules) { + + const slides = toArray(container.querySelectorAll("section")); + this.currentSlide = null; + + slides.forEach((slide) => { + const children = toArray(slide.childNodes); + const container = document.createElement("div"); + container.classList.add("slideContainer"); + children.forEach((child) => { + slide.removeChild(child); + container.appendChild(child); + }); + slide.appendChild(container); + }); + + function slideIndex(slide) { + return slides.indexOf(slide); + } + + this.deactivateSlide = (slide) => { + if (slide.classList.contains("current")) { + slide.classList.add("out"); + slide.classList.remove("current"); + } + this.currentSlide = null; + } + + this.activateSlide = (slide) => { + if (slide.classList.contains("out")) { + this.cleanupModules(slide); + slide.classList.remove("out"); + } + if (this.currentSlide !== null) this.deactivateSlide(slides[this.currentSlide]); + this.currentSlide = slideIndex(slide); + + this.activateModules(slide); + + slide.classList.add("current"); + slide.classList.add("in"); + window.location.hash = "" + this.currentSlide; + } + + this.nextSlide = () => { + let nextSlide = this.currentSlide !== null ? this.currentSlide + 1 : 0; + if (nextSlide >= slides.length) nextSlide = slides.length - 1; + if (nextSlide !== this.currentSlide) this.activateSlide(slides[nextSlide]); + } + + this.previousSlide = () => { + let prevSlide = this.currentSlide !== null ? this.currentSlide - 1 : 0; + if (prevSlide < 0) prevSlide = 0; + if (prevSlide !== this.currentSlide) this.activateSlide(slides[prevSlide]); + } + + this.initModules = (slide) => { + let slideData = slide.dataset, + deckData = container.dataset; + let mods = [], mod; + for (mod in deckModules) { + if (deckModules.hasOwnProperty(mod)) { + let arg = slideData.hasOwnProperty(mod) ? slideData[mod] : + deckData.hasOwnProperty(mod) ? deckData[mod] : null; + if (arg) mods.push(new deckModules[mod](slide, arg)); + } + } + slide._deck_modules = mods; + } + + this.activateModules = (slide) => { + slide._deck_modules.forEach((mod) => mod.activate && mod.activate()); + } + + this.stabiliseModules = (slide) => { + slide._deck_modules.forEach((mod) => mod.stabilise && mod.stabilise()); + } + + this.cleanupModules = (slide) => { + slide._deck_modules.forEach((mod) => mod.cleanup && mod.cleanup()); + } + + this.transitionEnd = (e) => { + let slide = e.target; + if (slide.classList.contains("out")) { + slide.classList.remove("out"); + this.cleanupModules(slide); + } else if (slide.classList.contains("in")) { + slide.classList.remove("in"); + this.stabiliseModules(slide); + } + } + + slides.forEach(((slide) => this.initModules(slide)).bind(this)); + + events.on(container, events.vendorPrefix("TransitionEnd"), this.transitionEnd, this); + + this.bind = (binding, callback) => { + mousetrap.bind(binding, callback.bind(this)); + }; + + this.bind(["pageup", "left"], this.previousSlide); + this.bind(["pagedown", "space", "right"], this.nextSlide); + + setTimeout(() => { + let match = /^#(\d+)$/.exec(window.location.hash); + if (match) { + this.activateSlide(slides[parseInt(match[1], 10)]); + } else { + this.nextSlide(); + } + }, 1); + +} + +module.exports = Deck; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/events.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/events.es6 new file mode 100644 index 0000000..b96c5a8 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/events.es6 @@ -0,0 +1,68 @@ +// Thanks http://lea.verou.me/2009/02/find-the-vendor-prefix-of-the-current-browser/ +var cachedPrefix = null; + +function getPrefix() { + if (cachedPrefix) return cachedPrefix; + const regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/; + const elem = document.body; + for (let prop in elem.style) { + if (regex.test(prop)) { + return cachedPrefix = prop.match(regex)[0]; + } + } + if ("WebkitOpacity" in elem.style) { + return cachedPrefix = "Webkit"; + } + if ("KhtmlOpacity" in elem.style) { + return cachedPrefix = "Khtml"; + } + return cachedPrefix = ""; +} + +var cachedEvents = {}; + +function vendorPrefix(prop) { + if (cachedEvents.hasOwnProperty(prop)) return cachedEvents[prop]; + const vp = getPrefix().toLowerCase(); + const pp = (vp) ? (vp + prop) : prop.toLowerCase(); + cachedEvents[prop] = pp; + return pp; +} + +// Register to receive events. +function on(emitter, eventName, handler, context) { + handler = context ? handler.bind(context) : handler; + emitter.addEventListener(eventName, handler); + return handler; +} + +// Register to receive one single event. +function once(emitter, eventName, handler, context) { + handler = context ? handler.bind(context) : handler; + let wrapper = function onceHandler(event) { + emitter.removeEventListener(eventName, onceHandler); + handler(event); + }; + emitter.addEventListener(eventName, wrapper); + return wrapper; +} + +// Register to receive events until the handler function returns true. +function until(emitter, eventName, handler, context) { + handler = context ? handler.bind(context) : handler; + let wrapper = function untilHandler(event) { + if (handler(event)) + emitter.removeEventListener(eventName, untilHandler); + }; + emitter.addEventListener(eventName, wrapper); + return wrapper; +} + +// Unregister an event handler. +function off(emitter, eventName, handler) { + emitter.removeEventListener(eventName, handler); +} + +module.exports = { + on: on, once: once, until: until, off: off, vendorPrefix: vendorPrefix +}; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/mousetrap.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/mousetrap.js new file mode 100644 index 0000000..530255e --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/mousetrap.js @@ -0,0 +1,944 @@ +/*global define:false */ +/** + * Copyright 2013 Craig Campbell + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.4.6 + * @url craig.is/killing/mice + */ +/** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ +var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' +}, + + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }, + + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }, + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }, + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + _REVERSE_MAP, + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + _callbacks = {}, + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + _directMap = {}, + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + _sequenceLevels = {}, + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + _resetTimer, + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + _ignoreNextKeyup = false, + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + _ignoreNextKeypress = false, + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + _nextExpectedAction = false; + +/** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ +for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; +} + +/** + * loop through to map numbers on the numeric keypad + */ +for (i = 0; i <= 9; ++i) { + _MAP[i + 96] = i; +} + +/** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ +function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); +} + +/** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ +function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); +} + +/** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ +function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); +} + +/** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ +function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } +} + +/** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ +function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i, + callback, + matches = [], + action = e.type; + + // if there are no events related to this keycode + if (!_callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < _callbacks[character].length; ++i) { + callback = _callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + _callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; +} + +/** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ +function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; +} + +/** + * prevents default for this event + * + * @param {Event} e + * @returns void + */ +function _preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + return; + } + + e.returnValue = false; +} + +/** + * stops propogation for this event + * + * @param {Event} e + * @returns void + */ +function _stopPropagation(e) { + if (e.stopPropagation) { + e.stopPropagation(); + return; + } + + e.cancelBubble = true; +} + +/** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ +function _fireCallback(callback, e, combo, sequence) { + + // if this event should not happen stop here + if (Mousetrap.stopCallback(e, e.target || e.srcElement, combo, sequence)) { + return; + } + + if (callback(e, combo) === false) { + _preventDefault(e); + _stopPropagation(e); + } +} + +/** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ +function _handleKey(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e), + i, + doNotReset = {}, + maxLevel = 0, + processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; +} + +/** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ +function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + Mousetrap.handleKey(character, _eventModifiers(e), e); +} + +/** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ +function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; +} + +/** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ +function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); +} + +/** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ +function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; +} + +/** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ +function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; +} + +/** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ +function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } +} + +/** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ +function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + return combination.split('+'); +} + +/** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ +function _getKeyInfo(combination, action) { + var keys, + key, + i, + modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; +} + +/** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ +function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + _directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '), + info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + _callbacks[info.key] = _callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + _callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); +} + +/** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ +function _bindMultiple(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } +} + +// start! +_addEvent(document, 'keypress', _handleKeyEvent); +_addEvent(document, 'keydown', _handleKeyEvent); +_addEvent(document, 'keyup', _handleKeyEvent); + +var Mousetrap = { + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + bind: function(keys, callback, action) { + keys = keys instanceof Array ? keys : [keys]; + _bindMultiple(keys, callback, action); + return this; + }, + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + unbind: function(keys, action) { + return Mousetrap.bind(keys, function() {}, action); + }, + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + trigger: function(keys, action) { + if (_directMap[keys + ':' + action]) { + _directMap[keys + ':' + action]({}, keys); + } + return this; + }, + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + reset: function() { + _callbacks = {}; + _directMap = {}; + return this; + }, + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + stopCallback: function(e, element) { + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }, + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + handleKey: _handleKey +}; + +module.exports = Mousetrap; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/text.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/text.es6 new file mode 100644 index 0000000..58034c9 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/lib/text.es6 @@ -0,0 +1,26 @@ +function minIndent(text) { + return text.split("\n").reduce(function(min, line) { + if (line.trim().length === 0) return min; + var indent = line.length - line.trimLeft().length; + return min === null ? indent : Math.min(min, indent); + }, null); +} + +function alignIndents(text) { + var indent = minIndent(text); + return text.split("\n").map(function(line) { + return line.slice(indent).trimRight(); + }).join("\n"); +} + +function cleanText(text, type) { + text = alignIndents(text); + while (text[0] === "\n") text = text.slice(1); + while (text[text.length-1] === "\n") text = text.slice(0, text.length - 1); + if (type === "html") { + text = text.replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&"); + } + return text + "\n"; +} + +module.exports = { cleanText: cleanText }; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/main.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/main.es6 new file mode 100644 index 0000000..b4044c5 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/main.es6 @@ -0,0 +1,9 @@ +window.global = window; +require("traceur/bin/traceur-runtime"); +require("./css/screen.less"); +var Deck = require("./deck"); +window.deck = new Deck(document.getElementById("slides"), { + "editor": require("./modules/editor"), + "background": require("./modules/background"), + "image": require("./modules/image") +}); diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/background.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/background.es6 new file mode 100644 index 0000000..88c77f8 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/background.es6 @@ -0,0 +1,35 @@ +/*global setTimeout */ + +var events = require("../lib/events"); + +function Background(slide, url) { + + const preload = document.createElement("img"); + preload.src = url; + + // --- activate + + this.activate = () => { + if (this.background) this.background.parentNode.removeChild(this.background); + this.background = document.createElement("div"); + this.background.classList.add("background"); + this.background.style.backgroundImage = "url(" + url + ")"; + slide.parentNode.appendChild(this.background); + setTimeout((() => { + this.background.classList.add("active"); + }).bind(this), 1); + } + + // --- cleanup + + this.cleanup = () => { + events.once(this.background, events.vendorPrefix("TransitionEnd"), () => { + this.background.parentNode.removeChild(this.background); + this.background = null; + }, this); + this.background.classList.remove("active"); + } + +} + +module.exports = Background; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor.es6 new file mode 100644 index 0000000..c44eff5 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor.es6 @@ -0,0 +1,258 @@ +/*global setTimeout, Audio */ + +require("codemirror/lib/codemirror.js"); +require("codemirror/lib/codemirror.css"); + +require("codemirror/addon/edit/matchbrackets.js"); +require("codemirror/addon/edit/closebrackets.js"); +require("codemirror/addon/hint/show-hint.js"); +require("codemirror/addon/hint/show-hint.css"); +require("codemirror/addon/hint/anyword-hint.js"); +require("codemirror/addon/selection/active-line.js"); +require("codemirror/addon/comment/comment.js"); +require("codemirror/addon/tern/tern.js"); +require("codemirror/addon/tern/tern.css"); + +require("codemirror/mode/javascript/javascript.js"); + +require("codemirror/theme/xq-light.css"); + +let CodeMirror = window.CodeMirror; // :( +window.tern = require("tern"); // ;((( + +var events = require("../lib/events"); +var text = require("../lib/text"); +var emacs = require("./editor/emacs"); +var es6ify = require("./editor/es6ify"); +var esprima = require("./editor/esprima"); +var Spinner = require("spin.js"); +var _ = require("underscore"); + +function Editor(slide, mode) { + const args = slide.dataset; + const target = slide.querySelector(".slideContainer"); + const initialCode = target.innerHTML; + + this.onTabClose = () => { + if (!this.cm.isClean()) { + return "The current buffer has modifications."; + } + }; + + // --- Comms + + this.send = (message) => { + this.targetFrame.contentWindow.postMessage(JSON.stringify(message), "*"); + }; + + this.compile = () => { + var js = es6ify.compile(this.cm.getDoc().getValue()); + this.cm.clearGutter(); + if (js.errors.length) { + new Audio(require("./editor/smb_bump.mp3")).play(); + for (let i = 0; i < js.errors.length; i++) { + let [all, file, line, ch, msg] = /^([^:]*):(\d+):(\d+): (.*)$/.exec(js.errors[i]); + line = parseInt(line, 10) -1; ch = parseInt(ch, 10) -1; + let marker = document.createElement("img"); + marker.title = msg; + marker.classList.add("cm-error"); + this.cm.setGutterMarker(line, "cm-errors", marker); + } + return null; + } else { + return js.js; + } + }; + + this.evalInFrame = (cm) => { + // FIXME select behaviour by language, don't assume JS + const js = this.compile(); + if (!js) return; + + if (args.reload !== undefined) { + this.targetFrame.src = args.href; + setTimeout((() => { + events.until(this.targetFrame.contentWindow, "message", function(e) { + if (e.data === "rdy lol") { + this.send({code: js}); + return true; + } + }, this); + }).bind(this), 100); + } else { + this.send({code: js}); + } + }; + + this.evalFormAtPoint = (cm) => { + // FIXME select behaviour by language, don't assume JS + const src = cm.getDoc().getValue(); + const tree = esprima.parse(src, { + tolerant: true, range: true + }); + const cur = cm.indexFromPos(cm.getCursor()); + tree.body + .filter((n) => cur >= n.range[0] && cur <= n.range[1]) + .forEach((n) => { + cm.getDoc().setSelection(cm.posFromIndex(n.range[0]), + cm.posFromIndex(n.range[1])); + var js = es6ify.compile(cm.getDoc().getSelection()); + if (js.errors.length) { + new Audio(require("./editor/smb_bump.mp3")).play(); + let marker = document.createElement("img"); + marker.title = js.errors[0]; + marker.classList.add("cm-error"); + this.cm.setGutterMarker(cm.posFromIndex(n.range[1]).line, "cm-errors", marker); + } else { + console.log(js.js); + this.send({code: js.js}); + } + }); + }; + + this.reloadFrame = (cm) => { + this.targetFrame.src = args.href; + }; + + // --- keybindings + + this.iframeBind = (key) => { + return (function() { this.send({ key: key }); }).bind(this); + }; + + const keymap = {}; + keymap["Ctrl-S"] = this.evalInFrame.bind(this); + keymap["Ctrl-D"] = this.evalFormAtPoint.bind(this); + keymap["Ctrl-R"] = this.reloadFrame.bind(this); + keymap["Alt-Space"] = this.iframeBind("space"); + keymap["Alt-Enter"] = this.iframeBind("enter"); + keymap["Alt-Up"] = this.iframeBind("up"); + keymap["Alt-Down"] = this.iframeBind("down"); + keymap["Alt-Left"] = this.iframeBind("left"); + keymap["Alt-Right"] = this.iframeBind("right"); + keymap["Ctrl-K"] = emacs.kill; + keymap["Ctrl-Y"] = emacs.yank; + keymap["Ctrl-A"] = "goLineStartSmart"; + keymap["Ctrl-E"] = "goLineEnd"; + keymap["Ctrl-,"] = "toggleComment"; + keymap.Tab = (cm) => cm.indentLine(cm.getDoc().getCursor().line); + keymap["Ctrl-\\"] = (cm) => CodeMirror.showHint(cm); + keymap["Ctrl-="] = (cm) => CodeMirror.showHint(cm); + keymap["Ctrl-'"] = (cm) => { + const cur = cm.getDoc().getCursor(); + const token = cm.getTokenAt(cur, true); + cm.getDoc().extendSelection({line: cur.line, ch: token.start}, + {line: cur.line, ch: token.end}); + } + keymap.Esc = (cm) => { + // wow, much hack + const input = document.createElement("input"); + input.setAttribute("type", "text"); + document.body.appendChild(input); + input.focus(); + input.parentNode.removeChild(input); + }; + + // --- CodeMirror config + + const options = { + value: text.cleanText(initialCode, "html"), + mode: mode, + extraKeys: keymap, + gutters: ["cm-errors"], + // lineNumbers: true, + lineWrapping: false, + // matchBrackets: true, + autoCloseBrackets: true, + styleActiveLine: true, + theme: "xq-light" + }; + + // --- activate + + this.activate = () => { + slide.classList.add("editor"); + target.innerHTML = ""; + + this.editorFrame = document.createElement("div"); + this.editorFrame.classList.add("editorFrame"); + target.appendChild(this.editorFrame); + + this.targetContainer = document.createElement("div"); + this.targetContainer.classList.add("targetFrame"); + + this.targetFrame = document.createElement("iframe"); + + this.loaderFrame = document.createElement("div"); + this.loaderFrame.classList.add("loaderFrame"); + this.targetContainer.appendChild(this.loaderFrame); + target.appendChild(this.targetContainer); + + const factor = Math.min(this.loaderFrame.clientWidth, + this.loaderFrame.clientHeight) / 13.25; + this.spinner = new Spinner({ + color: "white", + shadow: true, + hwaccel: true, + length: factor * 2, + radius: factor * 2, + width: factor, + trail: 40, + lines: 12 + }).spin(this.loaderFrame); + + this.cm = CodeMirror(this.editorFrame, options); + this.cm.setSize("100%", "100%"); + + if (mode === "text/javascript") { + let tern = new CodeMirror.TernServer({ + defs: [ require("tern/defs/ecma5.json"), + require("tern/defs/browser.json"), + require("./editor/mousetrap.json"), + require("./editor/rxjs.json") ] + }); + let ternKeymap = _.extend({}, keymap); + ternKeymap["Ctrl-\\"] = (cm) => tern.complete(cm); + ternKeymap["Ctrl-I"] = (cm) => tern.showType(cm); + ternKeymap["Alt-."] = (cm) => tern.jumpToDef(cm); + ternKeymap["Alt-,"] = (cm) => tern.jumpBack(cm); + ternKeymap["Ctrl-Q"] = (cm) => tern.rename(cm); + this.cm.setOption("extraKeys", ternKeymap); + this.cm.on("cursorActivity", (cm) => tern.updateArgHints(cm)); + } + } + + // --- stabilise + + this.stabilise = () => { + this.targetFrame.style.display = "none"; + this.targetFrame.src = args.href; + this.targetContainer.appendChild(this.targetFrame); + events.until(this.targetFrame.contentWindow, "message", function(e) { + if (e.data === "rdy lol") { + this.spinner.stop(); + this.targetFrame.style.display = ""; + this.targetContainer.removeChild(this.loaderFrame); + this.loaderFrame = this.spinner = null; + return true; + } + }, this); + this.cm.refresh(); + this.cleanupHandler = events.on(window, "beforeunload", this.onTabClose, this); + } + + // --- cleanup + + this.cleanup = () => { + if (this.cleanupHandler) { + events.off(this.cleanupHandler); + this.cleanupHandler = null; + } + this.cm = null; + target.innerHTML = initialCode; + target.classList.remove("editor"); + } + +} + +module.exports = Editor; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/client.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/client.js new file mode 100644 index 0000000..eeca35f --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/client.js @@ -0,0 +1,31 @@ +/*global setTimeout */ + +(function() { + var preservedState = {}; + function evalCode(code) { + setTimeout(function() { + var module = preservedState; + eval(code); + }, 1); + } + + function onMessage(e) { + var message; + try { + message = JSON.parse(e.data); + } catch(e) { + return; + } + + if (message.hasOwnProperty("key") && window.Mousetrap) { + Mousetrap.trigger(message.key); + } + + if (message.hasOwnProperty("code")) { + evalCode(message.code); + } + } + + window.addEventListener("message", onMessage); + window.postMessage("rdy lol", "*"); +})(); diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/emacs.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/emacs.es6 new file mode 100644 index 0000000..b97f39d --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/emacs.es6 @@ -0,0 +1,90 @@ +/*global CodeMirror */ + +// Copied from CodeMirror's Emacs keymap: +var killRing = []; +function addToRing(str) { + killRing.push(str); + if (killRing.length > 50) killRing.shift(); +} +function growRingTop(str) { + if (!killRing.length) return addToRing(str); + killRing[killRing.length - 1] += str; +} +function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; } +function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); } + +var lastKill = null; + +function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + +function kill(cm, from, to, mayGrow, text) { + if (text == null) text = cm.getRange(from, to); + + if (mayGrow && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) + growRingTop(text); + else + addToRing(text); + cm.replaceRange("", from, to, "+delete"); + + if (mayGrow) lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; + else lastKill = null; +} + +function getPrefix(cm, precise) { + var digits = cm.state.emacsPrefix; + if (!digits) return precise ? null : 1; + clearPrefix(cm); + return digits == "-" ? -1 : Number(digits); +} + +var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true}; + +function maybeClearPrefix(cm, arg) { + if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg)) + clearPrefix(cm); +} + +function clearPrefix(cm) { + cm.state.emacsPrefix = null; + cm.off("keyHandled", maybeClearPrefix); + cm.off("inputRead", maybeDuplicateInput); +} + +function maybeDuplicateInput(cm, event) { + var dup = getPrefix(cm); + if (dup > 1 && event.origin == "+input") { + var one = event.text.join("\n"), txt = ""; + for (var i = 1; i < dup; ++i) txt += one; + cm.replaceSelection(txt, "end", "+input"); + } +} + +function repeated(cmd) { + var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd; + return function(cm) { + var prefix = getPrefix(cm); + f(cm); + for (var i = 1; i < prefix; ++i) f(cm); + }; +} + +const killKey = repeated((cm) => { + var start = cm.getCursor(), end = cm.clipPos(CodeMirror.Pos(start.line)); + var text = cm.getRange(start, end); + if (!/\S/.test(text)) { + text += "\n"; + end = CodeMirror.Pos(start.line + 1, 0); + } + kill(cm, start, end, true, text); +}); + +const yankKey = (cm) => { + var start = cm.getCursor(); + cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste"); + cm.setSelection(start, cm.getCursor()); +}; + +module.exports = { + kill: killKey, + yank: yankKey +}; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/es6ify.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/es6ify.es6 new file mode 100644 index 0000000..7d93808 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/es6ify.es6 @@ -0,0 +1,42 @@ +/*global traceur */ + +var _ = require("underscore"); + +var traceurCode = require("raw!traceur/bin/traceur.js"); +('global', eval)(traceurCode); // I don't even + +const traceurOptions = { + modules: "commonjs", + filename: "repl.js", + blockBinding: true, + symbols: true, + deferredFunctions: true, + types: true, + annotations: true +}; + +function compile(code) { + traceur.options.reset(); + _.extend(traceur.options, traceurOptions); + + var errorReporter = new traceur.util.TestErrorReporter(); + var sourceFile = new traceur.syntax.SourceFile(traceurOptions.filename, code); + var parser = new traceur.syntax.Parser(sourceFile, errorReporter); + var tree = parser.parseModule(); + var transformer = new traceur.codegeneration.FromOptionsTransformer(errorReporter); + var transformedTree = transformer.transform(tree); + + if (errorReporter.hadError()) { + return { + js: null, + errors: errorReporter.errors + }; + } else { + return { + js: traceur.outputgeneration.TreeWriter.write(transformedTree), + errors: errorReporter.errors + }; + } +} + +module.exports = { compile: compile }; diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/esprima.js b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/esprima.js new file mode 100644 index 0000000..83951cf --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/esprima.js @@ -0,0 +1,5514 @@ +/* + Copyright (C) 2013 Ariya Hidayat + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, +parseClassExpression: true, parseClassDeclaration: true, parseExpression: true, +parseForStatement: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseImportSpecifier: true, +parseLeftHandSideExpression: true, parseParams: true, validateParam: true, +parseSpreadOrAssignmentExpression: true, +parseStatement: true, parseSourceElement: true, parseModuleBlock: true, parseConciseBody: true, +parseYieldExpression: true +*/ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PropertyKind, + Messages, + Regex, + SyntaxTreeDelegate, + ClassPropertyType, + source, + strict, + index, + lineNumber, + lineStart, + length, + delegate, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9, + Template: 10 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', + // assignment operators + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', + // binary/unary operators + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; + + Syntax = { + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + AssignmentExpression: 'AssignmentExpression', + BinaryExpression: 'BinaryExpression', + BlockStatement: 'BlockStatement', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ClassHeritage: 'ClassHeritage', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportDeclaration: 'ExportDeclaration', + ExportBatchSpecifier: 'ExportBatchSpecifier', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + ForStatement: 'ForStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportSpecifier: 'ImportSpecifier', + LabeledStatement: 'LabeledStatement', + Literal: 'Literal', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleDeclaration: 'ModuleDeclaration', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SwitchCase: 'SwitchCase', + SwitchStatement: 'SwitchStatement', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + ClassPropertyType = { + 'static': 'static', + prototype: 'prototype' + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedTemplate: 'Unexpected quasi %0', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInFormalsList: 'Invalid left-hand side in formals list', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition', + IllegalReturn: 'Illegal return statement', + IllegalYield: 'Illegal yield expression', + IllegalSpread: 'Illegal spread element', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list', + DefaultRestParameter: 'Rest parameter can not have a default value', + ElementAfterSpreadElement: 'Spread must be the final element of an element list', + ObjectPatternAsRestParameter: 'Invalid rest parameter', + ObjectPatternAsSpread: 'Invalid spread argument', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode', + NewlineAfterModule: 'Illegal newline after module', + NoFromAfterImport: 'Missing from after import', + InvalidModuleSpecifier: 'Invalid module specifier', + NestedModule: 'Module declaration can not be nested', + NoYieldInGenerator: 'Missing yield in generator', + NoUnintializedConst: 'Const must be initialized', + ComprehensionRequiresBlock: 'Comprehension must have at least one block', + ComprehensionError: 'Comprehension Error', + EachNotAllowed: 'Each is not supported' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), + NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 48 && ch <= 57); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === 32) || // space + (ch === 9) || // tab + (ch === 0xB) || + (ch === 0xC) || + (ch === 0xA0) || + (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch >= 48 && ch <= 57) || // 0..9 + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function skipComment() { + var ch, blockComment, lineComment; + + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source.charCodeAt(index); + + if (lineComment) { + ++index; + if (isLineTerminator(ch)) { + lineComment = false; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === 13 && source.charCodeAt(index + 1) === 10) { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source.charCodeAt(index++); + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + // Block comment ends with '*/' (char #42, char #47). + if (ch === 42) { + ch = source.charCodeAt(index); + if (ch === 47) { + ++index; + blockComment = false; + } + } + } + } else if (ch === 47) { + ch = source.charCodeAt(index + 1); + // Line comment starts with '//' (char #47, char #47). + if (ch === 47) { + index += 2; + lineComment = true; + } else if (ch === 42) { + // Block comment starts with '/*' (char #47, char #42). + index += 2; + blockComment = true; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + + function getEscapedIdentifier() { + var ch, id; + + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id = ch; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 92) { + // Blackslash (char #92) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (char #92) starts an escaped character. + id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + code = source.charCodeAt(index), + code2, + ch1 = source[index], + ch2, + ch3, + ch4; + + switch (code) { + // Check for most common single-character punctuators. + case 40: // ( open bracket + case 41: // ) close bracket + case 59: // ; semicolon + case 44: // , comma + case 123: // { open curly brace + case 125: // } close curly brace + case 91: // [ + case 93: // ] + case 58: // : + case 63: // ? + case 126: // ~ + ++index; + if (extra.tokenize) { + if (code === 40) { + extra.openParenToken = extra.tokens.length; + } else if (code === 123) { + extra.openCurlyToken = extra.tokens.length; + } + } + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (char #61) marks an assignment or comparison operator. + if (code2 === 61) { + switch (code) { + case 37: // % + case 38: // & + case 42: // *: + case 43: // + + case 45: // - + case 47: // / + case 60: // < + case 62: // > + case 94: // ^ + case 124: // | + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + case 33: // ! + case 61: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 61) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + default: + break; + } + } + break; + } + + // Peek more characters. + + ch2 = source[index + 1]; + ch3 = source[index + 2]; + ch4 = source[index + 3]; + + // 4-character punctuator: >>>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + if (ch4 === '=') { + index += 4; + return { + type: Token.Punctuator, + value: '>>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 3-character punctuators: === !== >>> <<= >>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + index += 3; + return { + type: Token.Punctuator, + value: '>>>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '<' && ch2 === '<' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '<<=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.' && ch2 === '.' && ch3 === '.') { + index += 3; + return { + type: Token.Punctuator, + value: '...', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Other 2-character punctuators: ++ -- << >> && || + + if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '=' && ch2 === '>') { + index += 2; + return { + type: Token.Punctuator, + value: '=>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (!octal && number.length === 0) { + // only 0o or 0O + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanNumericLiteral() { + var number, start, ch, octal; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (ch === 'b' || ch === 'B') { + ++index; + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (index < length) { + ch = source.charCodeAt(index); + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) { + return scanOctalLiteral(ch, start); + } + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDecimalDigit(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + } + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplate() { + var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal; + + terminated = false; + tail = false; + start = index; + + ++index; + + while (index < length) { + ch = source[index++]; + if (ch === '`') { + tail = true; + terminated = true; + break; + } else if (ch === '$') { + if (source[index] === '{') { + ++index; + terminated = true; + break; + } + cooked += ch; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + cooked += '\n'; + break; + case 'r': + cooked += '\r'; + break; + case 't': + cooked += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + cooked += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + cooked += unescaped; + } else { + index = restore; + cooked += ch; + } + } + break; + case 'b': + cooked += '\b'; + break; + case 'f': + cooked += '\f'; + break; + case 'v': + cooked += '\v'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + cooked += String.fromCharCode(code); + } else { + cooked += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + cooked += '\n'; + } else { + cooked += ch; + } + } + + if (!terminated) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.Template, + value: { + cooked: cooked, + raw: source.slice(start + 1, index - ((tail) ? 1 : 2)) + }, + tail: tail, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplateElement(option) { + var startsWith, template; + + lookahead = null; + skipComment(); + + startsWith = (option.head) ? '`' : '}'; + + if (source[index] !== startsWith) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + template = scanTemplate(); + + peek(); + + return template; + } + + function scanRegExp() { + var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + + lookahead = null; + skipComment(); + + start = index; + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + while (index < length) { + ch = source[index++]; + str += ch; + if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + pattern = str.substr(1, str.length - 2); + + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + } else { + str += '\\'; + } + } else { + flags += ch; + str += ch; + } + } + + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + + peek(); + + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + return { + literal: str, + value: value, + range: [start, index] + }; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return scanRegExp(); + } + if (prevToken.type === 'Punctuator') { + if (prevToken.value === ')') { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { + return scanRegExp(); + } + return scanPunctuator(); + } + if (prevToken.value === '}') { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return scanRegExp(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return scanRegExp(); + } + return scanRegExp(); + } + if (prevToken.type === 'Keyword') { + return scanRegExp(); + } + return scanPunctuator(); + } + + function advance() { + var ch; + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + range: [index, index] + }; + } + + ch = source.charCodeAt(index); + + // Very common: ( and ) and ; + if (ch === 40 || ch === 41 || ch === 58) { + return scanPunctuator(); + } + + // String literal starts with single quote (#39) or double quote (#34). + if (ch === 39 || ch === 34) { + return scanStringLiteral(); + } + + if (ch === 96) { + return scanTemplate(); + } + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + + // Dot (.) char #46 can also start a floating-point number, hence the need + // to check the next character. + if (ch === 46) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + // Slash (/) char #47 can also start a regex. + if (extra.tokenize && ch === 47) { + return advanceSlash(); + } + + return scanPunctuator(); + } + + function lex() { + var token; + + token = lookahead; + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = advance(); + + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + function lookahead2() { + var adv, pos, line, start, result; + + // If we are collecting the tokens, don't grab the next one yet. + adv = (typeof extra.advance === 'function') ? extra.advance : advance; + + pos = index; + line = lineNumber; + start = lineStart; + + // Scan for the next immediate token. + if (lookahead === null) { + lookahead = adv(); + } + index = lookahead.range[1]; + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + + // Grab the token right after. + result = adv(); + index = pos; + lineNumber = line; + lineStart = start; + + return result; + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + postProcess: function (node) { + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createForOfStatement: function (left, right, body) { + return { + type: Syntax.ForOfStatement, + left: left, + right: right, + body: body + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression + }; + }, + + createFunctionExpression: function (id, params, defaults, body, rest, generator, expression) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.range[0], token.range[1]) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value, method, shorthand) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind, + method: method, + shorthand: shorthand + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + }, + + createTemplateElement: function (value, tail) { + return { + type: Syntax.TemplateElement, + value: value, + tail: tail + }; + }, + + createTemplateLiteral: function (quasis, expressions) { + return { + type: Syntax.TemplateLiteral, + quasis: quasis, + expressions: expressions + }; + }, + + createSpreadElement: function (argument) { + return { + type: Syntax.SpreadElement, + argument: argument + }; + }, + + createTaggedTemplateExpression: function (tag, quasi) { + return { + type: Syntax.TaggedTemplateExpression, + tag: tag, + quasi: quasi + }; + }, + + createArrowFunctionExpression: function (params, defaults, body, rest, expression) { + return { + type: Syntax.ArrowFunctionExpression, + id: null, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: false, + expression: expression + }; + }, + + createMethodDefinition: function (propertyType, kind, key, value) { + return { + type: Syntax.MethodDefinition, + key: key, + value: value, + kind: kind, + 'static': propertyType === ClassPropertyType.static + }; + }, + + createClassBody: function (body) { + return { + type: Syntax.ClassBody, + body: body + }; + }, + + createClassExpression: function (id, superClass, body) { + return { + type: Syntax.ClassExpression, + id: id, + superClass: superClass, + body: body + }; + }, + + createClassDeclaration: function (id, superClass, body) { + return { + type: Syntax.ClassDeclaration, + id: id, + superClass: superClass, + body: body + }; + }, + + createExportSpecifier: function (id, name) { + return { + type: Syntax.ExportSpecifier, + id: id, + name: name + }; + }, + + createExportBatchSpecifier: function () { + return { + type: Syntax.ExportBatchSpecifier + }; + }, + + createExportDeclaration: function (declaration, specifiers, source) { + return { + type: Syntax.ExportDeclaration, + declaration: declaration, + specifiers: specifiers, + source: source + }; + }, + + createImportSpecifier: function (id, name) { + return { + type: Syntax.ImportSpecifier, + id: id, + name: name + }; + }, + + createImportDeclaration: function (specifiers, kind, source) { + return { + type: Syntax.ImportDeclaration, + specifiers: specifiers, + kind: kind, + source: source + }; + }, + + createYieldExpression: function (argument, delegate) { + return { + type: Syntax.YieldExpression, + argument: argument, + delegate: delegate + }; + }, + + createModuleDeclaration: function (id, source, body) { + return { + type: Syntax.ModuleDeclaration, + id: id, + source: source, + body: body + }; + } + + + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + assert(index < args.length, 'Message reference must be in range'); + return args[index]; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.range[0]; + error.lineNumber = token.lineNumber; + error.column = token.range[0] - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + error.description = msg; + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + if (token.type === Token.Template) { + throwError(token, Messages.UnexpectedTemplate, token.value.raw); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + + // Return true if the next token matches the specified contextual keyword + + function matchContextualKeyword(keyword) { + return lookahead.type === Token.Identifier && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line; + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + return; + } + + if (match(';')) { + lex(); + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + function isAssignableLeftHandSide(expr) { + return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true, body; + + expect('['); + while (!match(']')) { + if (lookahead.value === 'for' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + matchKeyword('for'); + tmp = parseForStatement({ignoreBody: true}); + tmp.of = tmp.type === Syntax.ForOfStatement; + tmp.type = Syntax.ComprehensionBlock; + if (tmp.left.kind) { // can't be let or const + throwError({}, Messages.ComprehensionError); + } + blocks.push(tmp); + } else if (lookahead.value === 'if' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + expectKeyword('if'); + expect('('); + filter = parseExpression(); + expect(')'); + } else if (lookahead.value === ',' && + lookahead.type === Token.Punctuator) { + possiblecomprehension = false; // no longer allowed. + lex(); + elements.push(null); + } else { + tmp = parseSpreadOrAssignmentExpression(); + elements.push(tmp); + if (tmp && tmp.type === Syntax.SpreadElement) { + if (!match(']')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) { + expect(','); // this lexes. + possiblecomprehension = false; + } + } + } + + expect(']'); + + if (filter && !blocks.length) { + throwError({}, Messages.ComprehensionRequiresBlock); + } + + if (blocks.length) { + if (elements.length !== 1) { + throwError({}, Messages.ComprehensionError); + } + return { + type: Syntax.ComprehensionExpression, + filter: filter, + blocks: blocks, + body: elements[0] + }; + } + return delegate.createArrayExpression(elements); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(options) { + var previousStrict, previousYieldAllowed, params, defaults, body; + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = options.generator; + params = options.params || []; + defaults = options.defaults || []; + + body = parseConciseBody(); + if (options.name && strict && isRestrictedWord(params[0].name)) { + throwErrorTolerant(options.name, Messages.StrictParamName); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(null, params, defaults, body, options.rest || null, options.generator, body.type !== Syntax.BlockStatement); + } + + + function parsePropertyMethodFunction(options) { + var previousStrict, tmp, method; + + previousStrict = strict; + strict = true; + + tmp = parseParams(); + + if (tmp.stricted) { + throwErrorTolerant(tmp.stricted, tmp.message); + } + + + method = parsePropertyFunction({ + params: tmp.params, + defaults: tmp.defaults, + rest: tmp.rest, + generator: options.generator + }); + + strict = previousStrict; + + return method; + } + + + function parseObjectPropertyKey() { + var token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseObjectProperty() { + var token, key, id, value, param; + + token = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + return delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false); + } + if (token.value === 'set' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + param = [ parseVariableIdentifier() ]; + expect(')'); + return delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false); + } + if (match(':')) { + lex(); + return delegate.createProperty('init', id, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false); + } + return delegate.createProperty('init', id, id, false, true); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + if (!match('*')) { + throwUnexpected(token); + } + lex(); + + id = parseObjectPropertyKey(); + + if (!match('(')) { + throwUnexpected(lex()); + } + + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false); + } + key = parseObjectPropertyKey(); + if (match(':')) { + lex(); + return delegate.createProperty('init', key, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false); + } + throwUnexpected(lex()); + } + + function parseObjectInitialiser() { + var properties = [], property, name, key, kind, map = {}, toString = String; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[key] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[key] |= kind; + } else { + map[key] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return delegate.createObjectExpression(properties); + } + + function parseTemplateElement(option) { + var token = scanTemplateElement(option); + if (strict && token.octal) { + throwError(token, Messages.StrictOctalLiteral); + } + return delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail); + } + + function parseTemplateLiteral() { + var quasi, quasis, expressions; + + quasi = parseTemplateElement({ head: true }); + quasis = [ quasi ]; + expressions = []; + + while (!quasi.tail) { + expressions.push(parseExpression()); + quasi = parseTemplateElement({ head: false }); + quasis.push(quasi); + } + + return delegate.createTemplateLiteral(quasis, expressions); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + ++state.parenthesizedCount; + + expr = parseExpression(); + + expect(')'); + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token; + + token = lookahead; + type = lookahead.type; + + if (type === Token.Identifier) { + lex(); + return delegate.createIdentifier(token.value); + } + + if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(lex()); + } + + if (type === Token.Keyword) { + if (matchKeyword('this')) { + lex(); + return delegate.createThisExpression(); + } + + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + + if (matchKeyword('class')) { + return parseClassExpression(); + } + + if (matchKeyword('super')) { + lex(); + return delegate.createIdentifier('super'); + } + } + + if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + return delegate.createLiteral(token); + } + + if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + return delegate.createLiteral(token); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('/') || match('/=')) { + return delegate.createLiteral(scanRegExp()); + } + + if (type === Token.Template) { + return parseTemplateLiteral(); + } + + return throwUnexpected(lex()); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = [], arg; + + expect('('); + + if (!match(')')) { + while (index < length) { + arg = parseSpreadOrAssignmentExpression(); + args.push(arg); + + if (match(')')) { + break; + } else if (arg.type === Syntax.SpreadElement) { + throwError({}, Messages.ElementAfterSpreadElement); + } + + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseSpreadOrAssignmentExpression() { + if (match('...')) { + lex(); + return delegate.createSpreadElement(parseAssignmentExpression()); + } + return parseAssignmentExpression(); + } + + function parseNonComputedProperty() { + var token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args; + + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return delegate.createNewExpression(callee, args); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + + function parseLeftHandSideExpression() { + var expr, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr = parseLeftHandSideExpressionAllowCall(), + token = lookahead; + + if (lookahead.type !== Token.Punctuator) { + return expr; + } + + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.createPostfixExpression(token.value, expr); + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + return parsePostfixExpression(); + } + + if (match('++') || match('--')) { + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + return delegate.createUnaryExpression(token.value, expr); + } + + if (match('+') || match('-') || match('~') || match('!')) { + token = lex(); + expr = parseUnaryExpression(); + return delegate.createUnaryExpression(token.value, expr); + } + + if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + return expr; + } + + return parsePostfixExpression(); + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + function parseBinaryExpression() { + var expr, token, prec, previousAllowIn, stack, right, operator, left, i; + + previousAllowIn = state.allowIn; + state.allowIn = true; + + expr = parseUnaryExpression(); + + token = lookahead; + prec = binaryPrecedence(token, previousAllowIn); + if (prec === 0) { + return expr; + } + token.prec = prec; + lex(); + + stack = [expr, token, parseUnaryExpression()]; + + while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + stack.push(delegate.createBinaryExpression(operator, left, right)); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + stack.push(parseUnaryExpression()); + } + + state.allowIn = previousAllowIn; + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + } + return expr; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate; + + expr = parseBinaryExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = delegate.createConditionalExpression(expr, consequent, alternate); + } + + return expr; + } + + // 11.13 Assignment Operators + + function reinterpretAsAssignmentBindingPattern(expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInAssignment); + } + reinterpretAsAssignmentBindingPattern(property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsAssignmentBindingPattern(element); + } + } + } else if (expr.type === Syntax.Identifier) { + if (isRestrictedWord(expr.name)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } else if (expr.type === Syntax.SpreadElement) { + reinterpretAsAssignmentBindingPattern(expr.argument); + if (expr.argument.type === Syntax.ObjectPattern) { + throwError({}, Messages.ObjectPatternAsSpread); + } + } else { + if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } + } + + + function reinterpretAsDestructuredParameter(options, expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInFormalsList); + } + reinterpretAsDestructuredParameter(options, property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsDestructuredParameter(options, element); + } + } + } else if (expr.type === Syntax.Identifier) { + validateParam(options, expr, expr.name); + } else { + if (expr.type !== Syntax.MemberExpression) { + throwError({}, Messages.InvalidLHSInFormalsList); + } + } + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, defaults, defaultCount, options, rest; + + params = []; + defaults = []; + defaultCount = 0; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + defaults.push(null); + validateParam(options, param, param.name); + } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) { + reinterpretAsDestructuredParameter(options, param); + params.push(param); + defaults.push(null); + } else if (param.type === Syntax.SpreadElement) { + assert(i === len - 1, 'It is guaranteed that SpreadElement is last element by parseExpression'); + reinterpretAsDestructuredParameter(options, param.argument); + rest = param.argument; + } else if (param.type === Syntax.AssignmentExpression) { + params.push(param.left); + defaults.push(param.right); + ++defaultCount; + validateParam(options, param.left, param.left.name); + } else { + return null; + } + } + + if (options.message === Messages.StrictParamDupe) { + throwError( + strict ? options.stricted : options.firstRestricted, + options.message + ); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { + params: params, + defaults: defaults, + rest: rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseArrowFunctionExpression(options) { + var previousStrict, previousYieldAllowed, body; + + expect('=>'); + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwError(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + throwErrorTolerant(options.stricted, options.message); + } + + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createArrowFunctionExpression(options.params, options.defaults, body, options.rest, body.type !== Syntax.BlockStatement); + } + + function parseAssignmentExpression() { + var expr, token, params, oldParenthesizedCount; + + if (matchKeyword('yield')) { + return parseYieldExpression(); + } + + oldParenthesizedCount = state.parenthesizedCount; + + if (match('(')) { + token = lookahead2(); + if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') { + params = parseParams(); + if (!match('=>')) { + throwUnexpected(lex()); + } + return parseArrowFunctionExpression(params); + } + } + + token = lookahead; + expr = parseConditionalExpression(); + + if (match('=>') && + (state.parenthesizedCount === oldParenthesizedCount || + state.parenthesizedCount === (oldParenthesizedCount + 1))) { + if (expr.type === Syntax.Identifier) { + params = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.SequenceExpression) { + params = reinterpretAsCoverFormalsList(expr.expressions); + } + if (params) { + return parseArrowFunctionExpression(params); + } + } + + if (matchAssign()) { + // 11.13.1 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + // ES.next draf 11.13 Runtime Semantics step 1 + if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) { + reinterpretAsAssignmentBindingPattern(expr); + } else if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + expr = delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression()); + } + + return expr; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr, expressions, sequence, coverFormalsList, spreadFound, oldParenthesizedCount; + + oldParenthesizedCount = state.parenthesizedCount; + + expr = parseAssignmentExpression(); + expressions = [ expr ]; + + if (match(',')) { + while (index < length) { + if (!match(',')) { + break; + } + + lex(); + expr = parseSpreadOrAssignmentExpression(); + expressions.push(expr); + + if (expr.type === Syntax.SpreadElement) { + spreadFound = true; + if (!match(')')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + break; + } + } + + sequence = delegate.createSequenceExpression(expressions); + } + + if (match('=>')) { + // Do not allow nested parentheses on the LHS of the =>. + if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) { + expr = expr.type === Syntax.SequenceExpression ? expr.expressions : expressions; + coverFormalsList = reinterpretAsCoverFormalsList(expr); + if (coverFormalsList) { + return parseArrowFunctionExpression(coverFormalsList); + } + } + throwUnexpected(lex()); + } + + if (spreadFound && lookahead2().value !== '=>') { + throwError({}, Messages.IllegalSpread); + } + + return sequence || expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block; + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseVariableDeclaration(kind) { + var id, + init = null; + if (match('{')) { + id = parseObjectInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else if (match('[')) { + id = parseArrayInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else { + id = state.allowKeyword ? parseNonComputedProperty() : parseVariableIdentifier(); + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + } + + if (kind === 'const') { + if (!match('=')) { + throwError({}, Messages.NoUnintializedConst); + } + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return delegate.createVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, kind); + } + + // http://wiki.ecmascript.org/doku.php?id=harmony:modules + + function parseModuleDeclaration() { + var id, src, body; + + lex(); // 'module' + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterModule); + } + + switch (lookahead.type) { + + case Token.StringLiteral: + id = parsePrimaryExpression(); + body = parseModuleBlock(); + src = null; + break; + + case Token.Identifier: + id = parseVariableIdentifier(); + body = null; + if (!matchContextualKeyword('from')) { + throwUnexpected(lex()); + } + lex(); + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + break; + } + + consumeSemicolon(); + return delegate.createModuleDeclaration(id, src, body); + } + + function parseExportBatchSpecifier() { + expect('*'); + return delegate.createExportBatchSpecifier(); + } + + function parseExportSpecifier() { + var id, name = null; + + id = parseVariableIdentifier(); + if (matchContextualKeyword('as')) { + lex(); + name = parseNonComputedProperty(); + } + + return delegate.createExportSpecifier(id, name); + } + + function parseExportDeclaration() { + var previousAllowKeyword, decl, def, src, specifiers; + + expectKeyword('export'); + + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'let': + case 'const': + case 'var': + case 'class': + case 'function': + return delegate.createExportDeclaration(parseSourceElement(), null, null); + } + } + + if (isIdentifierName(lookahead)) { + previousAllowKeyword = state.allowKeyword; + state.allowKeyword = true; + decl = parseVariableDeclarationList('let'); + state.allowKeyword = previousAllowKeyword; + return delegate.createExportDeclaration(decl, null, null); + } + + specifiers = []; + src = null; + + if (match('*')) { + specifiers.push(parseExportBatchSpecifier()); + } else { + expect('{'); + do { + specifiers.push(parseExportSpecifier()); + } while (match(',') && lex()); + expect('}'); + } + + if (matchContextualKeyword('from')) { + lex(); + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + } + + consumeSemicolon(); + + return delegate.createExportDeclaration(null, specifiers, src); + } + + function parseImportDeclaration() { + var specifiers, kind, src; + + expectKeyword('import'); + specifiers = []; + + if (isIdentifierName(lookahead)) { + kind = 'default'; + specifiers.push(parseImportSpecifier()); + + if (!matchContextualKeyword('from')) { + throwError({}, Messages.NoFromAfterImport); + } + lex(); + } else if (match('{')) { + kind = 'named'; + lex(); + do { + specifiers.push(parseImportSpecifier()); + } while (match(',') && lex()); + expect('}'); + + if (!matchContextualKeyword('from')) { + throwError({}, Messages.NoFromAfterImport); + } + lex(); + } + + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + + consumeSemicolon(); + + return delegate.createImportDeclaration(specifiers, kind, src); + } + + function parseImportSpecifier() { + var id, name = null; + + id = parseNonComputedProperty(); + if (matchContextualKeyword('as')) { + lex(); + name = parseVariableIdentifier(); + } + + return delegate.createImportSpecifier(id, name); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + return delegate.createEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + consumeSemicolon(); + return delegate.createExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return delegate.createIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return delegate.createDoWhileStatement(body, test); + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return delegate.createWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token = lex(), + declarations = parseVariableDeclarationList(); + + return delegate.createVariableDeclaration(declarations, token.value); + } + + function parseForStatement(opts) { + var init, test, update, left, right, body, operator, oldInIteration; + init = test = update = null; + expectKeyword('for'); + + // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each + if (matchContextualKeyword('each')) { + throwError({}, Messages.EachNotAllowed); + } + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = true; + + if (init.declarations.length === 1) { + if (matchKeyword('in') || matchContextualKeyword('of')) { + operator = lookahead; + if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = true; + + if (matchContextualKeyword('of')) { + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } else if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isAssignableLeftHandSide(init)) { + throwError({}, Messages.InvalidLHSInForIn); + } + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + if (!(opts !== undefined && opts.ignoreBody)) { + body = parseStatement(); + } + + state.inIteration = oldInIteration; + + if (typeof left === 'undefined') { + return delegate.createForStatement(init, test, update, body); + } + + if (operator.value === 'in') { + return delegate.createForInStatement(left, right, body); + } + return delegate.createForOfStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(index) === 59) { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement() { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement() { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(index) === 32) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return delegate.createReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return delegate.createReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return delegate.createReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return delegate.createWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, + consequent = [], + sourceElement; + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + consequent.push(sourceElement); + } + + return delegate.createSwitchCase(test, consequent); + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return delegate.createSwitchStatement(discriminant, cases); + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return delegate.createSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return delegate.createThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body; + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpected(lookahead); + } + + param = parseExpression(); + // 12.14.1 + if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return delegate.createCatchClause(param, body); + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return delegate.createTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return delegate.createDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key; + + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(); + case '{': + return parseBlock(); + case '(': + return parseExpressionStatement(); + default: + break; + } + } + + if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(); + case 'continue': + return parseContinueStatement(); + case 'debugger': + return parseDebuggerStatement(); + case 'do': + return parseDoWhileStatement(); + case 'for': + return parseForStatement(); + case 'function': + return parseFunctionDeclaration(); + case 'class': + return parseClassDeclaration(); + case 'if': + return parseIfStatement(); + case 'return': + return parseReturnStatement(); + case 'switch': + return parseSwitchStatement(); + case 'throw': + return parseThrowStatement(); + case 'try': + return parseTryStatement(); + case 'var': + return parseVariableStatement(); + case 'while': + return parseWhileStatement(); + case 'with': + return parseWithStatement(); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return delegate.createLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return delegate.createExpressionStatement(expr); + } + + // 13 Function Definition + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount; + + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + oldParenthesizedCount = state.parenthesizedCount; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + state.parenthesizedCount = 0; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesizedCount; + + return delegate.createBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, rest, param, def; + + token = lookahead; + if (token.value === '...') { + token = lex(); + rest = true; + } + + if (match('[')) { + param = parseArrayInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else if (match('{')) { + if (rest) { + throwError({}, Messages.ObjectPatternAsRestParameter); + } + param = parseObjectInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else { + param = parseVariableIdentifier(); + validateParam(options, token, token.value); + if (match('=')) { + if (rest) { + throwErrorTolerant(lookahead, Messages.DefaultRestParameter); + } + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } + } + + if (rest) { + if (!match(')')) { + throwError({}, Messages.ParameterAfterRestParameter); + } + options.rest = param; + return false; + } + + options.params.push(param); + options.defaults.push(def); + return !match(')'); + } + + function parseParams(firstRestricted) { + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + rest: null, + firstRestricted: firstRestricted + }; + + expect('('); + + if (!match(')')) { + options.paramSet = {}; + while (index < length) { + if (!parseParam(options)) { + break; + } + expect(','); + } + } + + expect(')'); + + if (options.defaultCount === 0) { + options.defaults = []; + } + + return options; + } + + function parseFunctionDeclaration() { + var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator; + + expectKeyword('function'); + + generator = false; + if (match('*')) { + lex(); + generator = true; + } + + token = lookahead; + + id = parseVariableIdentifier(); + + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + body = parseFunctionSourceElements(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false); + } + + function parseFunctionExpression() { + var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator; + + expectKeyword('function'); + + generator = false; + + if (match('*')) { + lex(); + generator = true; + } + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + body = parseFunctionSourceElements(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false); + } + + function parseYieldExpression() { + var delegateFlag, expr; + + expectKeyword('yield'); + + if (!state.yieldAllowed) { + throwErrorTolerant({}, Messages.IllegalYield); + } + + delegateFlag = false; + if (match('*')) { + lex(); + delegateFlag = true; + } + + expr = parseAssignmentExpression(); + state.yieldFound = true; + + return delegate.createYieldExpression(expr, delegateFlag); + } + + // 14 Classes + + function parseMethodDefinition(existingPropNames) { + var token, key, param, propType, isValidDuplicateProp = false; + + if (lookahead.value === 'static') { + propType = ClassPropertyType.static; + lex(); + } else { + propType = ClassPropertyType.prototype; + } + + if (match('*')) { + lex(); + return delegate.createMethodDefinition( + propType, + '', + parseObjectPropertyKey(), + parsePropertyMethodFunction({ generator: true }) + ); + } + + token = lookahead; + key = parseObjectPropertyKey(); + + if (token.value === 'get' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a setter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a getter for this prop + existingPropNames[propType][key.name].get === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a setter + && existingPropNames[propType][key.name].set !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].get = true; + + expect('('); + expect(')'); + return delegate.createMethodDefinition( + propType, + 'get', + key, + parsePropertyFunction({ generator: false }) + ); + } + if (token.value === 'set' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a getter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a setter for this prop + existingPropNames[propType][key.name].set === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a getter + && existingPropNames[propType][key.name].get !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].set = true; + + expect('('); + token = lookahead; + param = [ parseVariableIdentifier() ]; + expect(')'); + return delegate.createMethodDefinition( + propType, + 'set', + key, + parsePropertyFunction({ params: param, generator: false, name: token }) + ); + } + + // It is a syntax error if any other properties have the same name as a + // non-getter, non-setter method + if (existingPropNames[propType].hasOwnProperty(key.name)) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].data = true; + + return delegate.createMethodDefinition( + propType, + '', + key, + parsePropertyMethodFunction({ generator: false }) + ); + } + + function parseClassElement(existingProps) { + if (match(';')) { + lex(); + return; + } + return parseMethodDefinition(existingProps); + } + + function parseClassBody() { + var classElement, classElements = [], existingProps = {}; + + existingProps[ClassPropertyType.static] = {}; + existingProps[ClassPropertyType.prototype] = {}; + + expect('{'); + + while (index < length) { + if (match('}')) { + break; + } + classElement = parseClassElement(existingProps); + + if (typeof classElement !== 'undefined') { + classElements.push(classElement); + } + } + + expect('}'); + + return delegate.createClassBody(classElements); + } + + function parseClassExpression() { + var id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + if (!matchKeyword('extends') && !match('{')) { + id = parseVariableIdentifier(); + } + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassExpression(id, superClass, parseClassBody()); + } + + function parseClassDeclaration() { + var id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + id = parseVariableIdentifier(); + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassDeclaration(id, superClass, parseClassBody()); + } + + // 15 Program + + function matchModuleDeclaration() { + var id; + if (matchContextualKeyword('module')) { + id = lookahead2(); + return id.type === Token.StringLiteral || id.type === Token.Identifier; + } + return false; + } + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + case 'export': + return parseExportDeclaration(); + case 'import': + return parseImportDeclaration(); + default: + return parseStatement(); + } + } + + if (matchModuleDeclaration()) { + throwError({}, Messages.NestedModule); + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseProgramElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'export': + return parseExportDeclaration(); + case 'import': + return parseImportDeclaration(); + } + } + + if (matchModuleDeclaration()) { + return parseModuleDeclaration(); + } + + return parseSourceElement(); + } + + function parseProgramElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseProgramElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseProgramElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseModuleElement() { + return parseSourceElement(); + } + + function parseModuleElements() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseModuleElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseModuleBlock() { + var block; + + expect('{'); + + block = parseModuleElements(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + function parseProgram() { + var body; + strict = false; + peek(); + body = parseProgramElements(); + return delegate.createProgram(body); + } + + // The following functions are needed only when the option to preserve + // the comments is active. + + function addComment(type, value, start, end, loc) { + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (extra.comments.length > 0) { + if (extra.comments[extra.comments.length - 1].range[1] > start) { + return; + } + } + + extra.comments.push({ + type: type, + value: value, + range: [start, end], + loc: loc + }); + } + + function scanComment() { + var comment, ch, loc, start, blockComment, lineComment; + + comment = ''; + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch.charCodeAt(0))) { + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + lineComment = false; + addComment('Line', comment, start, index - 1, loc); + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + comment = ''; + } else if (index >= length) { + lineComment = false; + comment += ch; + loc.end = { + line: lineNumber, + column: length - lineStart + }; + addComment('Line', comment, start, length, loc); + } else { + comment += ch; + } + } else if (blockComment) { + if (isLineTerminator(ch.charCodeAt(0))) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + comment += '\r\n'; + } else { + comment += ch; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + comment += ch; + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + comment = comment.substr(0, comment.length - 1); + blockComment = false; + ++index; + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + comment = ''; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + start = index; + index += 2; + lineComment = true; + if (index >= length) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + lineComment = false; + addComment('Line', comment, start, index, loc); + } + } else if (ch === '*') { + start = index; + index += 2; + blockComment = true; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch.charCodeAt(0))) { + ++index; + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function filterCommentLocation() { + var i, entry, comment, comments = []; + + for (i = 0; i < extra.comments.length; ++i) { + entry = extra.comments[i]; + comment = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + comment.range = entry.range; + } + if (extra.loc) { + comment.loc = entry.loc; + } + comments.push(comment); + } + + extra.comments = comments; + } + + function collectToken() { + var start, loc, token, range, value; + + skipComment(); + start = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = extra.advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + range = [token.range[0], token.range[1]]; + value = source.slice(token.range[0], token.range[1]); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: range, + loc: loc + }); + } + + return token; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = extra.scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function LocationMarker() { + this.range = [index, index]; + this.loc = { + start: { + line: lineNumber, + column: index - lineStart + }, + end: { + line: lineNumber, + column: index - lineStart + } + }; + } + + LocationMarker.prototype = { + constructor: LocationMarker, + + end: function () { + this.range[1] = index; + this.loc.end.line = lineNumber; + this.loc.end.column = index - lineStart; + }, + + applyGroup: function (node) { + if (extra.range) { + node.groupRange = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.groupLoc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + }, + + apply: function (node) { + var nodeType = typeof node; + assert(nodeType === 'object', + 'Applying location marker to an unexpected node type: ' + + nodeType); + + if (extra.range) { + node.range = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.loc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + } + }; + + function createLocationMarker() { + return new LocationMarker(); + } + + function trackGroupExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + expect('('); + + ++state.parenthesizedCount; + expr = parseExpression(); + + expect(')'); + marker.end(); + marker.applyGroup(expr); + + return expr; + } + + function trackLeftHandSideExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function trackLeftHandSideExpressionAllowCall() { + var marker, expr, args; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + marker.end(); + marker.apply(expr); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function filterGroup(node) { + var n, i, entry; + + n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; + for (i in node) { + if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { + entry = node[i]; + if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { + n[i] = entry; + } else { + n[i] = filterGroup(entry); + } + } + } + return n; + } + + function wrapTrackingFunction(range, loc) { + + return function (parseFunction) { + + function isBinary(node) { + return node.type === Syntax.LogicalExpression || + node.type === Syntax.BinaryExpression; + } + + function visit(node) { + var start, end; + + if (isBinary(node.left)) { + visit(node.left); + } + if (isBinary(node.right)) { + visit(node.right); + } + + if (range) { + if (node.left.groupRange || node.right.groupRange) { + start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; + end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; + node.range = [start, end]; + } else if (typeof node.range === 'undefined') { + start = node.left.range[0]; + end = node.right.range[1]; + node.range = [start, end]; + } + } + if (loc) { + if (node.left.groupLoc || node.right.groupLoc) { + start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; + end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; + node.loc = { + start: start, + end: end + }; + node = delegate.postProcess(node); + } else if (typeof node.loc === 'undefined') { + node.loc = { + start: node.left.loc.start, + end: node.right.loc.end + }; + node = delegate.postProcess(node); + } + } + } + + return function () { + var marker, node; + + skipComment(); + + marker = createLocationMarker(); + node = parseFunction.apply(null, arguments); + marker.end(); + + if (range && typeof node.range === 'undefined') { + marker.apply(node); + } + + if (loc && typeof node.loc === 'undefined') { + marker.apply(node); + } + + if (isBinary(node)) { + visit(node); + } + + return node; + }; + }; + } + + function patch() { + + var wrapTracking; + + if (extra.comments) { + extra.skipComment = skipComment; + skipComment = scanComment; + } + + if (extra.range || extra.loc) { + + extra.parseGroupExpression = parseGroupExpression; + extra.parseLeftHandSideExpression = parseLeftHandSideExpression; + extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; + parseGroupExpression = trackGroupExpression; + parseLeftHandSideExpression = trackLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; + + wrapTracking = wrapTrackingFunction(extra.range, extra.loc); + + extra.parseArrayInitialiser = parseArrayInitialiser; + extra.parseAssignmentExpression = parseAssignmentExpression; + extra.parseBinaryExpression = parseBinaryExpression; + extra.parseBlock = parseBlock; + extra.parseFunctionSourceElements = parseFunctionSourceElements; + extra.parseCatchClause = parseCatchClause; + extra.parseComputedMember = parseComputedMember; + extra.parseConditionalExpression = parseConditionalExpression; + extra.parseConstLetDeclaration = parseConstLetDeclaration; + extra.parseExportBatchSpecifier = parseExportBatchSpecifier; + extra.parseExportDeclaration = parseExportDeclaration; + extra.parseExportSpecifier = parseExportSpecifier; + extra.parseExpression = parseExpression; + extra.parseForVariableDeclaration = parseForVariableDeclaration; + extra.parseFunctionDeclaration = parseFunctionDeclaration; + extra.parseFunctionExpression = parseFunctionExpression; + extra.parseParams = parseParams; + extra.parseImportDeclaration = parseImportDeclaration; + extra.parseImportSpecifier = parseImportSpecifier; + extra.parseModuleDeclaration = parseModuleDeclaration; + extra.parseModuleBlock = parseModuleBlock; + extra.parseNewExpression = parseNewExpression; + extra.parseNonComputedProperty = parseNonComputedProperty; + extra.parseObjectInitialiser = parseObjectInitialiser; + extra.parseObjectProperty = parseObjectProperty; + extra.parseObjectPropertyKey = parseObjectPropertyKey; + extra.parsePostfixExpression = parsePostfixExpression; + extra.parsePrimaryExpression = parsePrimaryExpression; + extra.parseProgram = parseProgram; + extra.parsePropertyFunction = parsePropertyFunction; + extra.parseSpreadOrAssignmentExpression = parseSpreadOrAssignmentExpression; + extra.parseTemplateElement = parseTemplateElement; + extra.parseTemplateLiteral = parseTemplateLiteral; + extra.parseStatement = parseStatement; + extra.parseSwitchCase = parseSwitchCase; + extra.parseUnaryExpression = parseUnaryExpression; + extra.parseVariableDeclaration = parseVariableDeclaration; + extra.parseVariableIdentifier = parseVariableIdentifier; + extra.parseMethodDefinition = parseMethodDefinition; + extra.parseClassDeclaration = parseClassDeclaration; + extra.parseClassExpression = parseClassExpression; + extra.parseClassBody = parseClassBody; + + parseArrayInitialiser = wrapTracking(extra.parseArrayInitialiser); + parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); + parseBinaryExpression = wrapTracking(extra.parseBinaryExpression); + parseBlock = wrapTracking(extra.parseBlock); + parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); + parseCatchClause = wrapTracking(extra.parseCatchClause); + parseComputedMember = wrapTracking(extra.parseComputedMember); + parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); + parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); + parseExportBatchSpecifier = wrapTracking(parseExportBatchSpecifier); + parseExportDeclaration = wrapTracking(parseExportDeclaration); + parseExportSpecifier = wrapTracking(parseExportSpecifier); + parseExpression = wrapTracking(extra.parseExpression); + parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); + parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); + parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); + parseParams = wrapTracking(extra.parseParams); + parseImportDeclaration = wrapTracking(extra.parseImportDeclaration); + parseImportSpecifier = wrapTracking(extra.parseImportSpecifier); + parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration); + parseModuleBlock = wrapTracking(extra.parseModuleBlock); + parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); + parseNewExpression = wrapTracking(extra.parseNewExpression); + parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); + parseObjectInitialiser = wrapTracking(extra.parseObjectInitialiser); + parseObjectProperty = wrapTracking(extra.parseObjectProperty); + parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); + parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); + parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); + parseProgram = wrapTracking(extra.parseProgram); + parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); + parseTemplateElement = wrapTracking(extra.parseTemplateElement); + parseTemplateLiteral = wrapTracking(extra.parseTemplateLiteral); + parseSpreadOrAssignmentExpression = wrapTracking(extra.parseSpreadOrAssignmentExpression); + parseStatement = wrapTracking(extra.parseStatement); + parseSwitchCase = wrapTracking(extra.parseSwitchCase); + parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); + parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); + parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); + parseMethodDefinition = wrapTracking(extra.parseMethodDefinition); + parseClassDeclaration = wrapTracking(extra.parseClassDeclaration); + parseClassExpression = wrapTracking(extra.parseClassExpression); + parseClassBody = wrapTracking(extra.parseClassBody); + } + + if (typeof extra.tokens !== 'undefined') { + extra.advance = advance; + extra.scanRegExp = scanRegExp; + + advance = collectToken; + scanRegExp = collectRegex; + } + } + + function unpatch() { + if (typeof extra.skipComment === 'function') { + skipComment = extra.skipComment; + } + + if (extra.range || extra.loc) { + parseArrayInitialiser = extra.parseArrayInitialiser; + parseAssignmentExpression = extra.parseAssignmentExpression; + parseBinaryExpression = extra.parseBinaryExpression; + parseBlock = extra.parseBlock; + parseFunctionSourceElements = extra.parseFunctionSourceElements; + parseCatchClause = extra.parseCatchClause; + parseComputedMember = extra.parseComputedMember; + parseConditionalExpression = extra.parseConditionalExpression; + parseConstLetDeclaration = extra.parseConstLetDeclaration; + parseExportBatchSpecifier = extra.parseExportBatchSpecifier; + parseExportDeclaration = extra.parseExportDeclaration; + parseExportSpecifier = extra.parseExportSpecifier; + parseExpression = extra.parseExpression; + parseForVariableDeclaration = extra.parseForVariableDeclaration; + parseFunctionDeclaration = extra.parseFunctionDeclaration; + parseFunctionExpression = extra.parseFunctionExpression; + parseImportDeclaration = extra.parseImportDeclaration; + parseImportSpecifier = extra.parseImportSpecifier; + parseGroupExpression = extra.parseGroupExpression; + parseLeftHandSideExpression = extra.parseLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; + parseModuleDeclaration = extra.parseModuleDeclaration; + parseModuleBlock = extra.parseModuleBlock; + parseNewExpression = extra.parseNewExpression; + parseNonComputedProperty = extra.parseNonComputedProperty; + parseObjectInitialiser = extra.parseObjectInitialiser; + parseObjectProperty = extra.parseObjectProperty; + parseObjectPropertyKey = extra.parseObjectPropertyKey; + parsePostfixExpression = extra.parsePostfixExpression; + parsePrimaryExpression = extra.parsePrimaryExpression; + parseProgram = extra.parseProgram; + parsePropertyFunction = extra.parsePropertyFunction; + parseTemplateElement = extra.parseTemplateElement; + parseTemplateLiteral = extra.parseTemplateLiteral; + parseSpreadOrAssignmentExpression = extra.parseSpreadOrAssignmentExpression; + parseStatement = extra.parseStatement; + parseSwitchCase = extra.parseSwitchCase; + parseUnaryExpression = extra.parseUnaryExpression; + parseVariableDeclaration = extra.parseVariableDeclaration; + parseVariableIdentifier = extra.parseVariableIdentifier; + parseMethodDefinition = extra.parseMethodDefinition; + parseClassDeclaration = extra.parseClassDeclaration; + parseClassExpression = extra.parseClassExpression; + parseClassBody = extra.parseClassBody; + } + + if (typeof extra.scanRegExp === 'function') { + advance = extra.advance; + scanRegExp = extra.scanRegExp; + } + } + + // This is used to modify the delegate. + + function extend(object, properties) { + var entry, result = {}; + + for (entry in object) { + if (object.hasOwnProperty(entry)) { + result[entry] = object[entry]; + } + } + + for (entry in properties) { + if (properties.hasOwnProperty(entry)) { + result[entry] = properties[entry]; + } + } + + return result; + } + + function tokenize(code, options) { + var toString, + token, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowKeyword: true, + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowKeyword: false, + allowIn: true, + labelSet: {}, + parenthesizedCount: 0, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + yieldAllowed: false, + yieldFound: false + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (extra.loc && options.source !== null && options.source !== undefined) { + delegate = extend(delegate, { + 'postProcess': function (node) { + node.loc.source = toString(options.source); + return node; + } + }); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + if (extra.range || extra.loc) { + program.body = filterGroup(program.body); + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + + return program; + } + + // Sync with *.json manifests. + exports.version = '1.1.0-dev-harmony'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/mousetrap.json b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/mousetrap.json new file mode 100644 index 0000000..26eab47 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/mousetrap.json @@ -0,0 +1,14 @@ +{ + "ExtendedKeyboardEvent": { + "returnValue": "boolean" + }, + "MousetrapStatic": { + "stopCallback": "fn(e: ExtendedKeyboardEvent, element: Element, combo: string) -> boolean", + "bind": "fn(keyArray: [string], callback: fn(e: ExtendedKeyboardEvent, combo: string) -> ?, action?: string)", + "unbind": "fn(keyArray: [string], action?: string)", + "trigger": "fn(keys: string, action?: string)", + "reset": "fn()" + }, + "Mousetrap": "MousetrapStatic", + "!name": "mousetrap.d.ts" +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/rxjs.json b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/rxjs.json new file mode 100644 index 0000000..eec4f01 --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/rxjs.json @@ -0,0 +1,424 @@ +{ + "Rx": { + "IDisposable": { + "dispose": "fn()" + }, + "Disposable": { + "action": "fn()", + "isDisposed": "bool", + "Disposable": "fn(action?: fn()) -> Disposable", + "dispose": "fn()", + "create": "fn(action?: fn()) -> Disposable", + "empty": { + "dispose": "fn()" + } + }, + "SingleAssignmentDisposable": { + "isDisposed": "bool", + "current": "Disposable", + "SingleAssignmentDisposable": "fn() -> SingleAssignmentDisposable", + "disposable": "fn(value: ?) -> Disposable", + "getDisposable": "fn() -> Disposable", + "setDisposable": "fn(value: IDisposable)", + "dispose": "fn()" + }, + "CompositeDisposable": { + "disposables": "[Disposable]", + "isDisposed": "bool", + "length": "number", + "CompositeDisposable": "fn(disposables: [Disposable]) -> CompositeDisposable", + "add": "fn(item: Disposable)", + "remove": "fn(item: Disposable) -> bool", + "dispose": "fn()", + "clear": "fn()", + "contains": "fn(item: ?) -> bool", + "toArray": "fn() -> [Disposable]" + }, + "SerialDisposable": { + "isDisposed": "bool", + "current": "Disposable", + "SerialDisposable": "fn() -> SerialDisposable", + "getDisposable": "fn() -> Disposable", + "setDisposable": "fn(value: Disposable)", + "disposable": "fn(value: Disposable) -> Disposable", + "dispose": "fn()" + }, + "RefCountDisposable": { + "RefCountDisposable": "fn(disposable: Disposable) -> RefCountDisposable", + "dispose": "fn()", + "getDisposable": "fn() -> Disposable" + }, + "Scheduler": { + "now": "number", + "Scheduler": "fn(now: ?, schedule: ?, scheduleRelative: ?, scheduleAbsolute: ?) -> Scheduler", + "invokeRecImmediate": "fn(scheduler: Scheduler, pair: ?) -> CompositeDisposable", + "invokeRecDate": "fn(scheduler: Scheduler, pair: ?, method: ?) -> CompositeDisposable", + "invokeAction": "fn(scheduler: Scheduler, action: fn()) -> Rx.Scheduler.invokeAction.!ret", + "catchException": "fn(handler: ?) -> CatchScheduler", + "schedulePeriodic": "fn(period: number, action: fn()) -> Disposable", + "schedulePeriodicWithState": "fn(state: ?, period: number, action: fn(state: ?)) -> Disposable", + "schedule": "fn(action: fn()) -> Disposable", + "scheduleWithState": "fn(state: ?, action: fn(state: ?)) -> Disposable", + "scheduleWithRelative": "fn(dueTime: number, action: fn()) -> Disposable", + "scheduleWithRelativeAndState": "fn(state: ?, dueTime: number, action: fn(state: ?)) -> Disposable", + "scheduleWithAbsolute": "fn(dueTime: number, action: fn()) -> Disposable", + "scheduleWithAbsoluteAndState": "fn(state: ?, dueTime: number, action: fn(state: ?)) -> Disposable", + "scheduleRecursive": "fn(action: fn()) -> Disposable", + "scheduleRecursiveWithState": "fn(state: ?, action: fn(state: ?, action: fn(state: ?))) -> Disposable", + "scheduleRecursiveWithRelative": "fn(dueTime: number, action: fn()) -> Disposable", + "scheduleRecursiveWithRelativeAndState": "fn(state: ?, dueTime: number, action: fn(state: ?, action: fn(state: ?, dueTime: number))) -> Disposable", + "scheduleRecursiveWithAbsolute": "fn(dueTime: number, action: fn(action: fn(dueTime: number))) -> Disposable", + "scheduleRecursiveWithAbsoluteAndState": "fn(state: ?, dueTime: number, action: fn(state: ?, action: fn(state: ?, dueTime: number))) -> Disposable", + "normalize": "fn(timeSpan: number) -> number", + "immediate": "fn() -> Scheduler", + "currentThread": "fn() -> Scheduler", + "timeout": "fn() -> Scheduler" + }, + "IndexedItem": { + "id": "number", + "value": "ScheduledItem", + "compareTo": "fn(other: IndexedItem) -> number" + }, + "ScheduledItem": { + "scheduler": "Scheduler", + "state": "?", + "action": "fn(scheduler: Scheduler, state: ?) -> Disposable", + "dueTime": "number", + "comparer": "fn(x: number, y: number) -> number", + "disposable": "SingleAssignmentDisposable", + "invoke": "fn()", + "compareTo": "fn(other: ScheduledItem) -> number", + "isCancelled": "fn() -> bool", + "invokeCore": "fn() -> Disposable" + }, + "PriorityQueue": { + "items": "[IndexedItem]", + "length": "number", + "isHigherPriority": "fn(left: number, right: number) -> bool", + "percolate": "fn(index: number)", + "heapify": "fn(index: number)", + "peek": "fn() -> IndexedItem", + "removeAt": "fn(index: number)", + "dequeue": "fn() -> IndexedItem", + "enqueue": "fn(item: IndexedItem)", + "remove": "fn(item: IndexedItem) -> bool" + }, + "VirtualTimeScheduler": { + "clock": "number", + "comparer": "fn(x: number, y: number) -> number", + "isEnabled": "bool", + "queue": "PriorityQueue", + "VirtualTimeScheduler": "fn(initialClock: number, comparer: fn(x: number, y: number) -> number) -> VirtualTimeScheduler", + "schedulePeriodicWithState": "fn(state: ?, period: number, action: fn(state: ?)) -> Disposable", + "scheduleRelativeWithState": "fn(state: ?, dueTime: number, action: fn(state: ?)) -> Disposable", + "scheduleRelative": "fn(dueTime: number, action: fn()) -> Disposable", + "start": "fn()", + "stop": "fn()", + "advanceTo": "fn(time: number)", + "advanceBy": "fn(time: number)", + "sleep": "fn(time: number)", + "getNext": "fn() -> ScheduledItem", + "scheduleAbsolute": "fn(dueTime: number, action: fn()) -> Disposable", + "scheduleAbsoluteWithState": "fn(state: ?, dueTime: number, action: fn(scheduler: Scheduler, state: ?) -> Disposable) -> Disposable" + }, + "CatchScheduler": {}, + "Notification": { + "hasValue": "bool", + "accept": "fn(onNext: fn(value: ?), onError?: fn(exception: ?), onCompleted?: fn())", + "toObservable": "fn(scheduler: Scheduler) -> Internals.AnonymousObservable", + "equals": "fn(other: Notification) -> bool", + "createOnNext": "fn(value: ?) -> Notification", + "createOnError": "fn(exception: ?) -> Notification", + "createOnCompleted": "fn() -> Notification" + }, + "Internals": { + "inherits": "fn(child: Function, parent: Function) -> Function", + "addRef": "fn(xs: ?, r: ?) -> AnonymousObservable", + "addProperties": "fn(obj: ?)", + "AbstractObserver": { + "isStopped": "bool", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()", + "fail": "fn() -> bool" + }, + "ScheduledObserver": { + "scheduler": "Scheduler", + "observer": "IObserver", + "isAcquired": "bool", + "hasFaulted": "bool", + "disposable": "SerialDisposable", + "ScheduledObserver": "fn(scheduler: Scheduler, observer: IObserver) -> ScheduledObserver" + }, + "Enumerator": { + "Enumerator": "fn(moveNext: fn() -> bool, getCurrent: fn() -> ?, dispose: fn()) -> Enumerator", + "moveNext": "fn() -> fn() -> bool", + "getCurrent": "fn() -> fn() -> ?", + "dispose": "fn() -> fn()", + "create": "fn(moveNext: fn() -> bool, getCurrent: fn() -> ?, dispose?: fn()) -> Enumerator" + }, + "Enumerable": { + "Enumerable": "fn(getEnumerator: fn() -> Enumerator) -> Enumerable", + "getEnumerator": "fn() -> fn() -> Enumerator", + "concat": "fn() -> AnonymousObservable", + "catchException": "fn() -> AnonymousObservable", + "repeat": "fn(value: ?, repeatCount?: number) -> Enumerable", + "forEach": "fn(source: Rx.Internals.Enumerable.forEach.source, selector?: fn(element: ?, index: number) -> ?) -> Enumerable" + }, + "AnonymousObservable": {} + }, + "ConnectableObservable": { + "connect": "fn() -> Disposable" + }, + "IObserver": { + "isStopped": "bool", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()" + }, + "Observer": { + "toNotifier": "fn() -> fn(any: ?)", + "asObserver": "fn() -> IObserver", + "checked": "fn() -> IObserver", + "create": "fn(onNext: fn(any: ?), onError?: fn(exception: ?), onCompleted?: fn()) -> IObserver", + "fromNotifier": "fn(handler: fn(value: ?)) -> IObserver" + }, + "AnonymousObserver": { + "AnonymousObserver": "fn(onNext: fn(value: ?), onError: fn(exception: ?), onCompleted: fn()) -> AnonymousObserver", + "next": "fn(value: ?)", + "error": "fn(exception: ?)", + "completed": "fn()" + }, + "Observable": { + "Observable": "fn(subscribe: fn(AnonymousObserver: ?) -> Internals.AnonymousObservable) -> Observable", + "finalValue": "fn() -> Internals.AnonymousObservable", + "subscribe": "fn(onNext: fn(value: ?), onError?: fn(exception: ?), onCompleted?: fn()) -> IObserver", + "toArray": "fn() -> Internals.AnonymousObservable", + "start": "fn(func: Function, scheduler?: Scheduler, context?: Object) -> Internals.AnonymousObservable", + "toAsync": "fn(func: Function, scheduler?: Scheduler, context?: Object) -> fn() -> Internals.AnonymousObservable", + "observeOn": "fn(scheduler: Scheduler) -> Internals.AnonymousObservable", + "subscribeOn": "fn(scheduler: Scheduler) -> Internals.AnonymousObservable", + "create": "fn(subscribe: fn(observer: AnonymousObserver) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "createWithDisposable": "fn(subscribe: fn(observer: AnonymousObserver) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "defer": "fn(observableFactory: fn() -> ?) -> Internals.AnonymousObservable", + "empty": "fn(scheduler?: Scheduler) -> Internals.AnonymousObservable", + "fromArray": "fn(array: [?], scheduler?: Scheduler) -> Internals.AnonymousObservable", + "generate": "fn(initialState: ?, condition: fn(value: ?) -> bool, iterate: fn(value: ?) -> ?, resultSelector: fn(value: ?) -> ?, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "never": "fn() -> Internals.AnonymousObservable", + "range": "fn(start: number, count: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "repeat": "fn(repeatCount?: number) -> Internals.AnonymousObservable", + "returnValue": "fn(value: ?, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "throwException": "fn(exception: Error, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "using": "fn(resourceFactory: fn() -> ?, observableFactory: fn(resource: ?) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "amb": "fn() -> Internals.AnonymousObservable", + "catchException": "fn(observables: [Internals.AnonymousObservable]) -> Internals.AnonymousObservable", + "combineLatest": "fn(second: Internals.AnonymousObservable, third: Internals.AnonymousObservable, fourth: Internals.AnonymousObservable, fifth: Internals.AnonymousObservable, resultSelector: fn(v1: ?, v2: ?, v3: ?, v4: ?, v5: ?) -> ?) -> Internals.AnonymousObservable", + "concat": "fn(observables: [Internals.AnonymousObservable]) -> Internals.AnonymousObservable", + "concatObservable": "fn() -> Internals.AnonymousObservable", + "merge": "fn(scheduler: Scheduler, observables: [Internals.AnonymousObservable]) -> Internals.AnonymousObservable", + "mergeObservable": "fn() -> Internals.AnonymousObservable", + "onErrorResumeNext": "fn(observables: [Internals.AnonymousObservable]) -> Internals.AnonymousObservable", + "skipUntil": "fn(other: Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "switchLatest": "fn() -> Internals.AnonymousObservable", + "takeUntil": "fn(other: Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "zip": "fn(second: [?], resultSelector: fn(left: ?, right: ?) -> ?) -> Internals.AnonymousObservable", + "asObservable": "fn() -> Internals.AnonymousObservable", + "bufferWithCount": "fn(count: number, skip?: number) -> Internals.AnonymousObservable", + "dematerialize": "fn() -> Internals.AnonymousObservable", + "distinctUntilChanged": "fn(keySelector?: fn(value: ?) -> ?, comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "doAction": "fn(observer: IObserver) -> Internals.AnonymousObservable", + "finallyAction": "fn(action: fn()) -> Internals.AnonymousObservable", + "ignoreElements": "fn() -> Internals.AnonymousObservable", + "materialize": "fn() -> Internals.AnonymousObservable", + "retry": "fn(retryCount?: number) -> Internals.AnonymousObservable", + "scan": "fn(seed: ?, accumulator: fn(acc: ?, x: ?) -> ?) -> Internals.AnonymousObservable", + "skipLast": "fn(count: number) -> Internals.AnonymousObservable", + "startWith": "fn(scheduler: Scheduler) -> Internals.AnonymousObservable", + "takeLast": "fn(count: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "takeLastBuffer": "fn(count: number) -> Internals.AnonymousObservable", + "windowWithCount": "fn(count: number, skip?: number) -> Internals.AnonymousObservable", + "defaultIfEmpty": "fn(defaultValue?: ?) -> Internals.AnonymousObservable", + "distinct": "fn(keySelector?: fn(element: ?) -> ?, keySerializer?: fn(key: ?) -> string) -> Internals.AnonymousObservable", + "groupBy": "fn(keySelector: fn(value: ?) -> ?, elementSelector?: fn(value: ?) -> ?, keySerializer?: fn(key: ?) -> string) -> Internals.AnonymousObservable", + "groupByUntil": "fn(keySelector: fn(value: ?) -> ?, elementSelector: fn(value: ?) -> ?, durationSelector: fn(group: GroupedObservable) -> Internals.AnonymousObservable, keySerializer?: fn(key: ?) -> string) -> Internals.AnonymousObservable", + "select": "fn(selector: fn(value: ?, index: number) -> ?) -> Internals.AnonymousObservable", + "map": "fn(selector: fn(value: ?, index: number) -> ?) -> Internals.AnonymousObservable", + "selectMany": "fn(selector: fn(value: ?) -> ?, resultSelector?: fn(value: ?, res: ?) -> ?) -> Internals.AnonymousObservable", + "flatMap": "fn(selector: fn(value: ?) -> ?, resultSelector?: fn(value: ?, res: ?) -> ?) -> Internals.AnonymousObservable", + "skip": "fn(count: number) -> Internals.AnonymousObservable", + "skipWhile": "fn(predicate: fn(value: ?, index?: number) -> bool) -> Internals.AnonymousObservable", + "take": "fn(count: number, scheduler: Scheduler) -> Internals.AnonymousObservable", + "takeWhile": "fn(predicate: fn(value: ?, index?: number) -> bool) -> Internals.AnonymousObservable", + "where": "fn(predicate: fn(value: ?, index?: number) -> bool) -> Internals.AnonymousObservable", + "aggregate": "fn(seed: ?, accumulator: fn(acc: ?, x: ?) -> ?) -> Internals.AnonymousObservable", + "any": "fn(predicate?: fn(any: ?) -> bool) -> Internals.AnonymousObservable", + "isEmpty": "fn() -> Internals.AnonymousObservable", + "all": "fn(predicate?: fn(any: ?) -> bool) -> Internals.AnonymousObservable", + "contains": "fn(value: ?, comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "count": "fn(predicate?: fn(any: ?) -> bool) -> Internals.AnonymousObservable", + "sum": "fn(keySelector?: fn(any: ?) -> ?) -> Internals.AnonymousObservable", + "minBy": "fn(keySelector: fn(value: ?) -> ?, comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "min": "fn(comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "maxBy": "fn(keySelector: fn(value: ?) -> ?, comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "max": "fn(comparer?: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "average": "fn(keySelector?: fn(value: ?) -> ?) -> Internals.AnonymousObservable", + "sequenceEqual": "fn(second: Internals.AnonymousObservable, comparer: fn(x: ?, y: ?) -> bool) -> Internals.AnonymousObservable", + "elementAt": "fn(index: number) -> Internals.AnonymousObservable", + "elementAtOrDefault": "fn(index: number, defaultValue?: ?) -> Internals.AnonymousObservable", + "single": "fn(predicate?: fn(value: ?) -> bool) -> Internals.AnonymousObservable", + "singleOrDefault": "fn(predicate?: fn(value: ?) -> bool, defaultValue?: ?) -> Internals.AnonymousObservable", + "first": "fn(predicate: fn(value: ?) -> bool) -> Internals.AnonymousObservable", + "firstOrDefault": "fn(predicate?: fn(value: ?) -> bool, defaultValue?: ?) -> Internals.AnonymousObservable", + "last": "fn(predicate?: fn(value: ?) -> bool) -> Internals.AnonymousObservable", + "lastOrDefault": "fn(predicate?: fn(value: ?) -> bool, defaultValue?: ?) -> Internals.AnonymousObservable", + "interval": "fn(period: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "timer": "fn(dueTime: number, period?: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "delay": "fn(dueTime: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "throttle": "fn(dueTime: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "windowWithTime": "fn(timeSpan: number, timeShiftScheduler?: ?, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "windowWithTimeOrCount": "fn(timeSpan: number, count: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "bufferWithTime": "fn(timeSpan: number, timeShiftScheduler?: Scheduler, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "bufferWithTimeOrCount": "fn(timeSpan: number, count: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "timeInterval": "fn(scheduler?: Scheduler) -> Internals.AnonymousObservable", + "timestamp": "fn(scheduler?: Scheduler) -> Internals.AnonymousObservable", + "sample": "fn(sampler: Internals.AnonymousObservable, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "timeout": "fn(dueTime: number, other: Internals.AnonymousObservable, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "generateWithAbsoluteTime": "fn(initialState: ?, condition: fn(state: ?) -> bool, iterate: fn(state: ?) -> ?, resultSelector: fn(state: ?) -> ?, timeSelector: fn(state: ?) -> Date, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "generateWithRelativeTime": "fn(initialState: ?, condition: fn(state: ?) -> bool, iterate: fn(state: ?) -> ?, resultSelector: fn(state: ?) -> ?, timeSelector: fn(state: ?) -> number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "delaySubscription": "fn(dueTime: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "delayWithSelector": "fn(subscriptionDelay: Internals.AnonymousObservable, delayDurationSelector: fn(x: ?) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "timeoutWithSelector": "fn(firstTimeout: Internals.AnonymousObservable, timeoutdurationSelector: fn(x: ?) -> Internals.AnonymousObservable, other?: Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "throttleWithSelector": "fn(throttleDurationSelector: fn(x: ?) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "skipLastWithTime": "fn(duration: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "takeLastWithTime": "fn(duration: number, timerScheduler?: Scheduler, loopScheduler?: Scheduler) -> Internals.AnonymousObservable", + "takeLastBufferWithTime": "fn(duration: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "takeWithTime": "fn(duration: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "skipWithTime": "fn(duration: ?, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "skipUntilWithTime": "fn(startTime: Date, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "takeUntilWithTime": "fn(endTime: Date, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "multicast": "fn(subject: Internals.AnonymousObservable, selector?: fn(source: Internals.AnonymousObservable) -> Internals.AnonymousObservable) -> Internals.AnonymousObservable", + "publish": "fn(selector?: fn(source: Internals.AnonymousObservable) -> Internals.AnonymousObservable) -> ConnectableObservable", + "publishLast": "fn(selector?: fn(source: Internals.AnonymousObservable) -> Internals.AnonymousObservable) -> ConnectableObservable", + "publishValue": "fn(initialValue: ?) -> ConnectableObservable", + "replay": "fn(selector?: fn(source: Internals.AnonymousObservable) -> Internals.AnonymousObservable, bufferSize?: number, window?: number, scheduler?: Scheduler) -> Internals.AnonymousObservable", + "and": "fn(right: Internals.AnonymousObservable) -> Pattern", + "then": "fn(selector: fn() -> ?) -> Plan", + "when": "fn() -> Internals.AnonymousObservable" + }, + "GroupedObservable": { + "key": "?", + "underlyingObservable": "Internals.AnonymousObservable" + }, + "InnerSubscription": { + "observer": "AnonymousObserver", + "subject": "Subject", + "InnerSubscription": "fn(subject: Subject, observer: AnonymousObserver) -> InnerSubscription", + "dispose": "fn()" + }, + "ISubject": {}, + "Subject": { + "isDisposed": "bool", + "isStopped": "bool", + "observers": "[AnonymousObserver]", + "Subject": "fn() -> Subject", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()" + }, + "AsyncSubject": { + "isDisposed": "bool", + "isStopped": "bool", + "value": "?", + "hasValue": "bool", + "observers": "[AnonymousObserver]", + "exception": "?", + "AsyncSubject": "fn() -> AsyncSubject", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()" + }, + "BehaviorSubject": { + "isDisposed": "bool", + "isStopped": "bool", + "value": "?", + "hasValue": "bool", + "observers": "[AnonymousObserver]", + "exception": "?", + "BehaviorSubject": "fn(value: ?) -> BehaviorSubject", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()" + }, + "ReplaySubject": { + "bufferSize": "number", + "window": "number", + "scheduler": "Scheduler", + "q": "[?]", + "observers": "[Internals.AnonymousObservable]", + "isStopped": "bool", + "isDisposed": "bool", + "hasError": "bool", + "error": "?", + "ReplaySubject": "fn(bufferSize?: number, window?: number, scheduler?: Scheduler) -> ReplaySubject", + "onNext": "fn(value: ?)", + "onError": "fn(error: ?)", + "onCompleted": "fn()", + "dispose": "fn()" + }, + "Pattern": { + "patterns": "[Internals.AnonymousObservable]", + "and": "fn(other: Internals.AnonymousObservable) -> Pattern", + "then": "fn(selector: fn() -> ?) -> Plan" + }, + "Plan": { + "expression": "[Internals.AnonymousObservable]", + "selector": "fn(values: ?) -> ?", + "activate": "fn(externalSubscriptions: ?, observer: ?, deactivate: ?) -> ActivePlan" + }, + "ActivePlan": { + "joinObserverArray": "[JoinObserver]", + "onNext": "fn(value: ?) -> ?", + "onCompleted": "fn()", + "joinObservers": "Map", + "dequeue": "fn()", + "match": "fn()" + }, + "Map": { + "keys": "[?]", + "values": "[?]", + "delete": "fn(key: ?) -> bool", + "get": "fn(key: ?, fallback: ?) -> ?", + "set": "fn(key: ?, value: ?)", + "size": "fn() -> number", + "has": "fn(key: ?) -> bool", + "getKeys": "fn() -> [?]", + "getValues": "fn() -> [?]" + }, + "JoinObserver": { + "source": "Internals.AnonymousObservable", + "queue": "[?]", + "activePlans": "[ActivePlan]", + "subscription": "SingleAssignmentDisposable", + "isDisposed": "bool", + "next": "fn(notification: ?)", + "addActivePlan": "fn(activePlan: ActivePlan)", + "subscribe": "fn()", + "removeActivePlan": "fn(activePlan: ?)" + } + }, + "!name": "rx.d.ts", + "!define": { + "Rx.Scheduler.invokeAction.!ret": { + "dispose": "fn()" + }, + "Rx.Internals.Enumerable.forEach.source": { + "length": "number", + "__item": "fn(index: number) -> ?" + } + } +} diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/smb_bump.mp3 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/smb_bump.mp3 new file mode 100644 index 0000000..4c39195 Binary files /dev/null and b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/editor/smb_bump.mp3 differ diff --git a/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/image.es6 b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/image.es6 new file mode 100644 index 0000000..bba2fcc --- /dev/null +++ b/2014_11_20_Bodil_Stokke_Reactive_Game_Development_For_The_Discerning_Hipster/src/modules/image.es6 @@ -0,0 +1,7 @@ +function Image(slide, url) { + + slide.style.backgroundImage = "url(" + url + ")"; + +} + +module.exports = Image; diff --git a/2015_03_26_Tomas_Petricek_Domain_Specific_Languages_FSharp/README.md b/2015_03_26_Tomas_Petricek_Domain_Specific_Languages_FSharp/README.md new file mode 100644 index 0000000..0a15d2e --- /dev/null +++ b/2015_03_26_Tomas_Petricek_Domain_Specific_Languages_FSharp/README.md @@ -0,0 +1,3 @@ +# Domain specific languages in FSharp + +Code obtained from [github.com/tpetricek/Documents](https://github.com/tpetricek/Documents/tree/master/Talks%202014/DSL%20(NDC%20Oslo)). diff --git a/README.md b/README.md index 0eadc42..4995531 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ Y Soft Technology Hours ======================= -Archive of presentations taken during Technology Hours. More about the meetup can be found at [initial presentation](https://speakerdeck.com/jfojtl/y-soft-technology-hour). +Archive of code samples and/or presentations taken during [Technology Hour](http://meetup.com/ysoft-th/)s. More about the meetup can be found at [initial presentation](https://speakerdeck.com/jfojtl/y-soft-technology-hour).